summaryrefslogtreecommitdiff
path: root/firmware/target/arm/rk27xx
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/rk27xx')
-rw-r--r--firmware/target/arm/rk27xx/adc-target.h4
-rw-r--r--firmware/target/arm/rk27xx/debug-target.h4
-rw-r--r--firmware/target/arm/rk27xx/hm60x/button-hm60x.c46
-rw-r--r--firmware/target/arm/rk27xx/hm60x/button-target.h44
-rw-r--r--firmware/target/arm/rk27xx/hm60x/lcd-hm60x.c148
-rw-r--r--firmware/target/arm/rk27xx/hm60x/power-hm60x.c48
-rw-r--r--firmware/target/arm/rk27xx/hm60x/powermgmt-hm60x.c66
-rw-r--r--firmware/target/arm/rk27xx/lcdif-rk27xx.c161
-rw-r--r--firmware/target/arm/rk27xx/lcdif-rk27xx.h11
-rw-r--r--firmware/target/arm/rk27xx/pcm-rk27xx.c62
-rw-r--r--firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c (renamed from firmware/target/arm/rk27xx/lcd-rk27xx.c)131
11 files changed, 596 insertions, 129 deletions
diff --git a/firmware/target/arm/rk27xx/adc-target.h b/firmware/target/arm/rk27xx/adc-target.h
index f6b8c98bb9..c359f3d7df 100644
--- a/firmware/target/arm/rk27xx/adc-target.h
+++ b/firmware/target/arm/rk27xx/adc-target.h
@@ -24,8 +24,8 @@
#define NUM_ADC_CHANNELS 4
#define ADC_BATTERY 0
-#define ADC_UNKNOWN_1 1
-#define ADC_UNKNOWN_2 2
+#define ADC_BUTTONS 1
+#define ADC_UNKNOWN 2
#define ADC_VREF 3 /* that is what datasheet says */
#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */
diff --git a/firmware/target/arm/rk27xx/debug-target.h b/firmware/target/arm/rk27xx/debug-target.h
index a507e96fdc..c083b9282a 100644
--- a/firmware/target/arm/rk27xx/debug-target.h
+++ b/firmware/target/arm/rk27xx/debug-target.h
@@ -24,7 +24,11 @@
#include <stdbool.h>
+#ifdef RK27_GENERIC
#define DEBUG_CANCEL BUTTON_VOL
+#elif defined(HM60X)
+#define DEBUG_CANCEL BUTTON_LEFT
+#endif
bool dbg_hw_info(void);
bool dbg_ports(void);
diff --git a/firmware/target/arm/rk27xx/hm60x/button-hm60x.c b/firmware/target/arm/rk27xx/hm60x/button-hm60x.c
new file mode 100644
index 0000000000..eaadaa131c
--- /dev/null
+++ b/firmware/target/arm/rk27xx/hm60x/button-hm60x.c
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Andrew Ryabinin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "system.h"
+#include "button.h"
+#include "adc.h"
+
+void button_init_device(void) {
+ /* setup button gpio as input */
+ GPIO_PCCON &= ~(POWEROFF_BUTTON);
+}
+
+int button_read_device(void) {
+ int adc_val = adc_read(ADC_BUTTONS);
+ if (adc_val < 30) {
+ return BUTTON_UP | (GPIO_PCDR & POWEROFF_BUTTON);
+ } else if (adc_val < 250) {
+ return BUTTON_RIGHT | (GPIO_PCDR & POWEROFF_BUTTON);
+ } else if (adc_val < 380) {
+ return BUTTON_LEFT | (GPIO_PCDR & POWEROFF_BUTTON);
+ } else if (adc_val < 450) {
+ return BUTTON_DOWN | (GPIO_PCDR & POWEROFF_BUTTON);
+ } else if (adc_val < 560) {
+ return BUTTON_PLAY | (GPIO_PCDR & POWEROFF_BUTTON);
+ }
+ return (GPIO_PCDR & POWEROFF_BUTTON);
+}
diff --git a/firmware/target/arm/rk27xx/hm60x/button-target.h b/firmware/target/arm/rk27xx/hm60x/button-target.h
new file mode 100644
index 0000000000..0209e0637d
--- /dev/null
+++ b/firmware/target/arm/rk27xx/hm60x/button-target.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Andrew Ryabinin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _BUTTON_TARGET_H_
+#define _BUTTON_TARGET_H_
+
+#include <stdbool.h>
+#include "config.h"
+
+void button_init_device(void);
+int button_read_device(void);
+
+
+#define BUTTON_UP 0x00000001
+#define BUTTON_DOWN 0x00000004
+#define BUTTON_LEFT 0x00000008
+#define BUTTON_RIGHT 0x00000010
+#define BUTTON_PLAY 0x00000020
+
+
+#define BUTTON_REMOTE 0
+
+
+#define POWEROFF_BUTTON 0x02
+#define POWEROFF_COUNT 30
+
+#endif /* _BUTTON_TARGET_H_ */
diff --git a/firmware/target/arm/rk27xx/hm60x/lcd-hm60x.c b/firmware/target/arm/rk27xx/hm60x/lcd-hm60x.c
new file mode 100644
index 0000000000..932154da8d
--- /dev/null
+++ b/firmware/target/arm/rk27xx/hm60x/lcd-hm60x.c
@@ -0,0 +1,148 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Andrew Ryabinin
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "kernel.h"
+#include "lcd.h"
+#include "system.h"
+#include "cpu.h"
+#include "lcdif-rk27xx.h"
+
+
+/* TODO */
+static void lcd_sleep(unsigned int sleep)
+{
+ (void)sleep;
+}
+
+void lcd_display_init()
+{
+ unsigned int x, y;
+
+ /* Driving ability setting */
+ lcd_write_reg(0x60, 0x00);
+ lcd_write_reg(0x61, 0x06);
+ lcd_write_reg(0x62, 0x00);
+ lcd_write_reg(0x63, 0xC8);
+
+ /* Gamma 2.2 Setting */
+ lcd_write_reg(0x40, 0x00);
+ lcd_write_reg(0x41, 0x40);
+ lcd_write_reg(0x42, 0x45);
+ lcd_write_reg(0x43, 0x01);
+ lcd_write_reg(0x44, 0x60);
+ lcd_write_reg(0x45, 0x05);
+ lcd_write_reg(0x46, 0x0C);
+ lcd_write_reg(0x47, 0xD1);
+ lcd_write_reg(0x48, 0x05);
+
+ lcd_write_reg(0x50, 0x75);
+ lcd_write_reg(0x51, 0x01);
+ lcd_write_reg(0x52, 0x67);
+ lcd_write_reg(0x53, 0x14);
+ lcd_write_reg(0x54, 0xF2);
+ lcd_write_reg(0x55, 0x07);
+ lcd_write_reg(0x56, 0x03);
+ lcd_write_reg(0x57, 0x49);
+
+ /* Power voltage setting */
+ lcd_write_reg(0x1F, 0x03);
+ lcd_write_reg(0x20, 0x00);
+ lcd_write_reg(0x24, 0x28);
+ lcd_write_reg(0x25, 0x45);
+
+ lcd_write_reg(0x23, 0x2F);
+
+ /* Power on setting */
+ lcd_write_reg(0x18, 0x44);
+ lcd_write_reg(0x21, 0x01);
+ lcd_write_reg(0x01, 0x00);
+ lcd_write_reg(0x1C, 0x03);
+ lcd_write_reg(0x19, 0x06);
+ udelay(5);
+
+ /* Display on setting */
+ lcd_write_reg(0x26, 0x84);
+ udelay(40);
+ lcd_write_reg(0x26, 0xB8);
+ udelay(40);
+ lcd_write_reg(0x26, 0xBC);
+ udelay(40);
+
+ /* Memmory access setting */
+ lcd_write_reg(0x16, 0x48);
+ /* Setup 16bit mode */
+ lcd_write_reg(0x17, 0x05);
+
+ /* Set GRAM area */
+ lcd_write_reg(0x02, 0x00);
+ lcd_write_reg(0x03, 0x00);
+ lcd_write_reg(0x04, 0x00);
+ lcd_write_reg(0x05, LCD_HEIGHT - 1);
+ lcd_write_reg(0x06, 0x00);
+ lcd_write_reg(0x07, 0x00);
+ lcd_write_reg(0x08, 0x00);
+ lcd_write_reg(0x09, LCD_WIDTH - 1);
+
+ /* Start GRAM write */
+ lcd_cmd(0x22);
+
+ for (x=0; x<LCD_WIDTH; x++)
+ for(y=0; y<LCD_HEIGHT; y++)
+ lcd_data(0x00);
+
+ lcd_sleep(0);
+}
+
+
+
+void lcd_update_rect(int x, int y, int width, int height)
+{
+ int px = x, py = y;
+ int pxmax = x + width, pymax = y + height;
+
+ lcd_write_reg(0x03, y);
+ lcd_write_reg(0x05, pymax-1);
+ lcd_write_reg(0x07, x);
+ lcd_write_reg(0x09, pxmax-1);
+
+ lcd_cmd(0x22);
+
+ for (px=x; px<pxmax; px++)
+ for (py=y; py<pymax; py++)
+ lcd_data(lcd_framebuffer[py][px]);
+}
+
+/* Blit a YUV bitmap directly to the LCD */
+void lcd_blit_yuv(unsigned char * const src[3],
+ int src_x, int src_y, int stride,
+ int x, int y, int width, int height)
+{
+ (void)src;
+ (void)src_x;
+ (void)src_y;
+ (void)stride;
+ (void)x;
+ (void)y;
+ (void)width;
+ (void)height;
+}
diff --git a/firmware/target/arm/rk27xx/hm60x/power-hm60x.c b/firmware/target/arm/rk27xx/hm60x/power-hm60x.c
new file mode 100644
index 0000000000..5c2abeb121
--- /dev/null
+++ b/firmware/target/arm/rk27xx/hm60x/power-hm60x.c
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright © 2009 Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdbool.h>
+#include "config.h"
+#include "inttypes.h"
+#include "power.h"
+#include "panic.h"
+#include "system.h"
+#include "usb_core.h" /* for usb_charging_maxcurrent_change */
+
+void power_off(void)
+{
+
+}
+
+void power_init(void)
+{
+ GPIO_PCDR |= (1<<0);
+ GPIO_PCCON |= (1<<0);
+}
+
+unsigned int power_input_status(void)
+{
+ return (usb_detect() == USB_INSERTED) ? POWER_INPUT_MAIN_CHARGER : POWER_INPUT_NONE;
+}
+
+bool charging_state(void)
+{
+ return true;
+}
diff --git a/firmware/target/arm/rk27xx/hm60x/powermgmt-hm60x.c b/firmware/target/arm/rk27xx/hm60x/powermgmt-hm60x.c
new file mode 100644
index 0000000000..7b5b171ccb
--- /dev/null
+++ b/firmware/target/arm/rk27xx/hm60x/powermgmt-hm60x.c
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright © 2009 Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "adc.h"
+#include "adc-target.h"
+#include "powermgmt.h"
+
+/* Battery voltage calculation and discharge/charge curves for the Meizu M3.
+
+ Battery voltage is calculated under the assumption that the adc full-scale
+ readout represents 3.00V and that the battery ADC channel is fed with
+ exactly half of the battery voltage (through a resistive divider).
+ Discharge and charge curves have not been calibrated yet.
+*/
+
+const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
+{
+ /* TODO: this is just an initial guess */
+ 3400
+};
+
+const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
+{
+ /* TODO: this is just an initial guess */
+ 3300
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
+{
+ /* TODO: simple uncalibrated curve, linear except for first 10% */
+ { 3300, 3600, 3665, 3730, 3795, 3860, 3925, 3990, 4055, 4120, 4185 }
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
+const unsigned short percent_to_volt_charge[11] =
+ /* TODO: simple uncalibrated curve, linear except for first 10% */
+ { 3300, 3600, 3665, 3730, 3795, 3860, 3925, 3990, 4055, 4120, 4185 };
+
+/* full-scale ADC readout (2^10) in millivolt */
+#define BATTERY_SCALE_FACTOR 6000
+
+/* Returns battery voltage from ADC [millivolts] */
+unsigned int battery_adc_voltage(void)
+{
+ return (adc_read(ADC_BATTERY) * BATTERY_SCALE_FACTOR) >> 10;
+}
diff --git a/firmware/target/arm/rk27xx/lcdif-rk27xx.c b/firmware/target/arm/rk27xx/lcdif-rk27xx.c
new file mode 100644
index 0000000000..aeee63ee7e
--- /dev/null
+++ b/firmware/target/arm/rk27xx/lcdif-rk27xx.c
@@ -0,0 +1,161 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Marcin Bukat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "kernel.h"
+#include "lcd.h"
+#include "system.h"
+#include "cpu.h"
+#include "lcdif-rk27xx.h"
+
+
+unsigned int lcd_data_transform(unsigned int data)
+{
+ unsigned int r, g, b;
+
+#if defined(RK27_GENERIC)
+ /* 18 bit interface */
+ r = (data & 0x0000fc00)<<8;
+ /* g = ((data & 0x00000300) >> 2) | ((data & 0x000000e0) >> 3); */
+ g = ((data & 0x00000300) << 6) | ((data & 0x000000e0) << 5);
+ b = (data & 0x00000001f) << 3;
+#elif defined(HM60X)
+ /* 16 bit interface */
+ r = (data & 0x0000f800) << 8;
+ g = (data & 0x000007e0) << 5;
+ b = (data & 0x0000001f) << 3;
+#else
+#error "Unknown target"
+#endif
+
+ return (r | g | b);
+}
+
+void lcd_cmd(unsigned int cmd)
+{
+ LCD_COMMAND = lcd_data_transform(cmd);
+}
+
+void lcd_data(unsigned int data)
+{
+ LCD_DATA = lcd_data_transform(data);
+}
+
+void lcd_write_reg(unsigned int reg, unsigned int val)
+{
+ lcd_cmd(reg);
+ lcd_data(val);
+}
+
+static void lcdctrl_bypass(unsigned int on_off)
+{
+ while (!(LCDC_STA & LCDC_MCU_IDLE));
+
+ if (on_off)
+ MCU_CTRL |= MCU_CTRL_BYPASS;
+ else
+ MCU_CTRL &= ~MCU_CTRL_BYPASS;
+}
+
+/* This part is unclear. I am unable to use buffered/FIFO based writes
+ * to lcd. Depending on settings of IF I get various patterns on display
+ * but not what I want to display apparently.
+ */
+static void lcdctrl_init(void)
+{
+ /* alpha b111
+ * stop at current frame complete
+ * MCU mode
+ * 24b RGB
+ */
+ LCDC_CTRL = ALPHA(7) | LCDC_STOP | LCDC_MCU | RGB24B;
+ MCU_CTRL = ALPHA_BASE(0x3f) | MCU_CTRL_BYPASS;
+
+ HOR_ACT = LCD_WIDTH + 3; /* define horizonatal active region */
+ VERT_ACT = LCD_HEIGHT; /* define vertical active region */
+ VERT_PERIOD = 0xfff; /* CSn/WEn/RDn signal timings */
+
+ LINE0_YADDR = LINE_ALPHA_EN | 0x7fe;
+ LINE1_YADDR = LINE_ALPHA_EN | ((1 * LCD_WIDTH) - 2);
+ LINE2_YADDR = LINE_ALPHA_EN | ((2 * LCD_WIDTH) - 2);
+ LINE3_YADDR = LINE_ALPHA_EN | ((3 * LCD_WIDTH) - 2);
+
+ LINE0_UVADDR = 0x7fe + 1;
+ LINE1_UVADDR = ((1 * LCD_WIDTH) - 2 + 1);
+ LINE2_UVADDR = ((2 * LCD_WIDTH) - 2 + 1);
+ LINE3_UVADDR = ((3 * LCD_WIDTH) - 2 + 1);
+
+#if 0
+ LINE0_YADDR = 0;
+ LINE1_YADDR = (1 * LCD_WIDTH);
+ LINE2_YADDR = (2 * LCD_WIDTH);
+ LINE3_YADDR = (3 * LCD_WIDTH);
+
+ LINE0_UVADDR = 1;
+ LINE1_UVADDR = (1 * LCD_WIDTH) + 1;
+ LINE2_UVADDR = (2 * LCD_WIDTH) + 1;
+ LINE3_UVADDR = (3 * LCD_WIDTH) + 1;
+
+ START_X = 0;
+ START_Y = 0;
+ DELTA_X = 0x200; /* no scaling */
+ DELTA_Y = 0x200; /* no scaling */
+#endif
+ LCDC_INTR_MASK = INTR_MASK_LINE; /* INTR_MASK_EVENLINE; */
+}
+
+/* configure pins to drive lcd in 18bit mode */
+static void iomux_lcd(void)
+{
+ unsigned long muxa;
+
+ muxa = SCU_IOMUXA_CON & ~(IOMUX_LCD_VSYNC|IOMUX_LCD_DEN|0xff);
+ muxa |= IOMUX_LCD_D18|IOMUX_LCD_D20|IOMUX_LCD_D22|IOMUX_LCD_D17|IOMUX_LCD_D16;
+
+ SCU_IOMUXA_CON = muxa;
+ SCU_IOMUXB_CON |= IOMUX_LCD_D815;
+}
+
+void lcd_init_device()
+{
+ iomux_lcd(); /* setup pins for 16bit lcd interface */
+ lcdctrl_init(); /* basic lcdc module configuration */
+
+ lcdctrl_bypass(1); /* run in bypass mode - all writes goes directly to lcd controller */
+ lcd_display_init();
+}
+
+/* This is ugly hack. We drive lcd in bypass mode
+ * where all writes goes directly to lcd controller.
+ * This is suboptimal at best. IF module povides
+ * FIFO, internal sram buffer, hardware scaller,
+ * DMA signals, hardware alpha blending and more.
+ * BUT the fact is that I have no idea how to use
+ * this modes. Datasheet floating around is very
+ * unclean in this regard and OF uses ackward
+ * lcd update routines which are hard to understand.
+ * Moreover OF sets some bits in IF module registers
+ * which are referred as reseved in datasheet.
+ */
+void lcd_update()
+{
+ lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
+}
diff --git a/firmware/target/arm/rk27xx/lcdif-rk27xx.h b/firmware/target/arm/rk27xx/lcdif-rk27xx.h
new file mode 100644
index 0000000000..caf97c8e94
--- /dev/null
+++ b/firmware/target/arm/rk27xx/lcdif-rk27xx.h
@@ -0,0 +1,11 @@
+#ifndef _LCDIF_RK27XX_H
+#define _LCDIF_RK27XX_H
+
+unsigned int lcd_data_transform(unsigned int data);
+
+void lcd_cmd(unsigned int cmd);
+void lcd_data(unsigned int data);
+void lcd_write_reg(unsigned int reg, unsigned int val);
+void lcd_display_init(void);
+
+#endif /* _LCDIF_RK27XX_H */
diff --git a/firmware/target/arm/rk27xx/pcm-rk27xx.c b/firmware/target/arm/rk27xx/pcm-rk27xx.c
index b8ae56adaf..80a8d462ea 100644
--- a/firmware/target/arm/rk27xx/pcm-rk27xx.c
+++ b/firmware/target/arm/rk27xx/pcm-rk27xx.c
@@ -8,6 +8,7 @@
* $Id$
*
* Copyright (C) 2011 Marcin Bukat
+ * Copyright (C) 2011 Andrew Ryabinin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -179,13 +180,65 @@ static void i2s_init(void)
(0<<2) | /* normal operation */
#ifdef CODEC_SLAVE
(1<<1) | /* start Tx (master mode) */
- (1<<0); /* start Rx (master mode) */
+ (0<<0); /* do not start Rx (master mode) */
+ /* setting Rx bit to 1 result in choppy audio */
#else
(0<<1) | /* not used in slave mode */
(0<<0); /* not used in slave mode */
#endif
}
+#ifdef CODEC_SLAVE
+/* When codec is slave we need to setup i2s MCLK clock using codec pll.
+ * The MCLK frequency is 256*codec frequency as i2s setup is:
+ * LRCK/SCLK = 64 and MCLK/SCLK = 4 (see i2s_init() for reference)
+ *
+ * PLL output frequency:
+ * Fout = ((Fref / (CLKR+1)) * (CLKF+1)) / (CLKOD+1)
+ * Fref = 24 MHz
+ */
+static void set_codec_freq(unsigned int freq)
+{
+ long timeout;
+
+ /* {CLKR, CLKF, CLKOD, CODECPLL_DIV} */
+ static const unsigned int pcm_freq_params[HW_NUM_FREQ][4] =
+ {
+ [HW_FREQ_96] = {24, 255, 4, 1},
+ [HW_FREQ_48] = {24, 127, 4, 1},
+ [HW_FREQ_44] = {24, 293, 4, 4},
+ [HW_FREQ_32] = {24, 127, 4, 2},
+ [HW_FREQ_24] = {24, 127, 4, 3},
+ [HW_FREQ_22] = {24, 146, 4, 4},
+ [HW_FREQ_16] = {24, 127, 5, 4},
+ [HW_FREQ_12] = {24, 127, 4, 7},
+ [HW_FREQ_11] = {24, 146, 4, 9},
+ [HW_FREQ_8] = {24, 127, 5, 9},
+ };
+ /* select divider output from codec pll */
+ SCU_DIVCON1 &= ~((1<<9) | (0xF<<5));
+ SCU_DIVCON1 |= (pcm_freq_params[freq][3]<<5);
+
+ /* Codec PLL power up */
+ SCU_PLLCON3 &= ~(1<<22);
+
+ SCU_PLLCON3 = (1<<24) | /* Saturation behavior enable */
+ (1<<23) | /* Enable fast locking circuit */
+ (pcm_freq_params[freq][0]<<16) | /* CLKR factor */
+ (pcm_freq_params[freq][1]<<4) | /* CLKF factor */
+ (pcm_freq_params[freq][2]<<1) ; /* CLKOD factor */
+
+/* wait for CODEC PLL lock with 10 ms timeout
+ * datasheet states that pll lock should take approx. 0.3 ms
+ */
+ timeout = current_tick + (HZ/100);
+ while (!(SCU_STATUS & (1<<2)))
+ if (TIME_AFTER(current_tick, timeout))
+ break;
+
+}
+#endif
+
void pcm_play_dma_init(void)
{
/* unmask HDMA interrupt in INTC */
@@ -204,8 +257,11 @@ void pcm_play_dma_postinit(void)
void pcm_dma_apply_settings(void)
{
- /* I2S module runs in slave mode */
- return;
+#ifdef CODEC_SLAVE
+ set_codec_freq(pcm_fsel);
+#endif
+
+ audiohw_set_frequency(pcm_fsel);
}
size_t pcm_get_bytes_waiting(void)
diff --git a/firmware/target/arm/rk27xx/lcd-rk27xx.c b/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c
index fda95e3174..b184630ebe 100644
--- a/firmware/target/arm/rk27xx/lcd-rk27xx.c
+++ b/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c
@@ -25,7 +25,9 @@
#include "system.h"
#include "cpu.h"
#include "spfd5420a.h"
+#include "lcdif-rk27xx.h"
+/* TODO: convert to udelay() */
static inline void delay_nop(int cycles)
{
asm volatile ("1: subs %[n], %[n], #1 \n\t"
@@ -34,17 +36,6 @@ static inline void delay_nop(int cycles)
: [n] "r" (cycles));
}
-static unsigned int lcd_data_transform(unsigned int data)
-{
- /* 18 bit interface */
- unsigned int r, g, b;
- r = (data & 0x0000fc00)<<8;
- /* g = ((data & 0x00000300) >> 2) | ((data & 0x000000e0) >> 3); */
- g = ((data & 0x00000300) << 6) | ((data & 0x000000e0) << 5);
- b = (data & 0x00000001f) << 3;
-
- return (r | g | b);
-}
/* converts RGB565 pixel into internal lcd bus format */
static unsigned int lcd_pixel_transform(unsigned short rgb565)
@@ -57,93 +48,8 @@ static unsigned int lcd_pixel_transform(unsigned short rgb565)
return r<<19 | g<<10 | b<<3;
}
-static void lcd_cmd(unsigned int cmd)
-{
- LCD_COMMAND = lcd_data_transform(cmd);
-}
-
-static void lcd_data(unsigned int data)
-{
- LCD_DATA = lcd_data_transform(data);
-}
-
-static void lcd_write_reg(unsigned int reg, unsigned int val)
-{
- lcd_cmd(reg);
- lcd_data(val);
-}
-
-static void lcdctrl_bypass(unsigned int on_off)
-{
- while (!(LCDC_STA & LCDC_MCU_IDLE));
-
- if (on_off)
- MCU_CTRL |= MCU_CTRL_BYPASS;
- else
- MCU_CTRL &= ~MCU_CTRL_BYPASS;
-}
-
-/* This part is unclear. I am unable to use buffered/FIFO based writes
- * to lcd. Depending on settings of IF I get various patterns on display
- * but not what I want to display apparently.
- */
-static void lcdctrl_init(void)
-{
- /* alpha b111
- * stop at current frame complete
- * MCU mode
- * 24b RGB
- */
- LCDC_CTRL = ALPHA(7) | LCDC_STOP | LCDC_MCU | RGB24B;
- MCU_CTRL = ALPHA_BASE(0x3f) | MCU_CTRL_BYPASS;
-
- HOR_ACT = 400 + 3; /* define horizonatal active region */
- VERT_ACT = 240; /* define vertical active region */
- VERT_PERIOD = 0xfff; /* CSn/WEn/RDn signal timings */
-
- LINE0_YADDR = LINE_ALPHA_EN | 0x7fe;
- LINE1_YADDR = LINE_ALPHA_EN | ((1 * 400) - 2);
- LINE2_YADDR = LINE_ALPHA_EN | ((2 * 400) - 2);
- LINE3_YADDR = LINE_ALPHA_EN | ((3 * 400) - 2);
-
- LINE0_UVADDR = 0x7fe + 1;
- LINE1_UVADDR = ((1 * 400) - 2 + 1);
- LINE2_UVADDR = ((2 * 400) - 2 + 1);
- LINE3_UVADDR = ((3 * 400) - 2 + 1);
-
-#if 0
- LINE0_YADDR = 0;
- LINE1_YADDR = (1 * 400);
- LINE2_YADDR = (2 * 400);
- LINE3_YADDR = (3 * 400);
-
- LINE0_UVADDR = 1;
- LINE1_UVADDR = (1 * 400) + 1;
- LINE2_UVADDR = (2 * 400) + 1;
- LINE3_UVADDR = (3 * 400) + 1;
-
- START_X = 0;
- START_Y = 0;
- DELTA_X = 0x200; /* no scaling */
- DELTA_Y = 0x200; /* no scaling */
-#endif
- LCDC_INTR_MASK = INTR_MASK_LINE; /* INTR_MASK_EVENLINE; */
-}
-
-/* configure pins to drive lcd in 18bit mode */
-static void iomux_lcd(void)
-{
- unsigned long muxa;
-
- muxa = SCU_IOMUXA_CON & ~(IOMUX_LCD_VSYNC|IOMUX_LCD_DEN|0xff);
- muxa |= IOMUX_LCD_D18|IOMUX_LCD_D20|IOMUX_LCD_D22|IOMUX_LCD_D17|IOMUX_LCD_D16;
-
- SCU_IOMUXA_CON = muxa;
- SCU_IOMUXB_CON |= IOMUX_LCD_D815;
-}
-
/* not tested */
-static void lcd_sleep(unsigned int sleep)
+static void lcd_sleep(bool sleep)
{
if (sleep)
{
@@ -165,15 +71,10 @@ static void lcd_sleep(unsigned int sleep)
lcd_cmd(GRAM_WRITE);
}
-void lcd_init_device()
+void lcd_display_init()
{
unsigned int x, y;
- iomux_lcd(); /* setup pins for 18bit lcd interface */
- lcdctrl_init(); /* basic lcdc module configuration */
-
- lcdctrl_bypass(1); /* run in bypass mode - all writes goes directly to lcd controller */
-
lcd_write_reg(RESET, 0x0001);
delay_nop(10000);
lcd_write_reg(RESET, 0x0000);
@@ -265,31 +166,13 @@ void lcd_init_device()
/* clear screen */
lcd_cmd(GRAM_WRITE);
- for (x=0; x<400; x++)
- for(y=0; y<240; y++)
+ for (x=0; x<LCD_WIDTH; x++)
+ for(y=0; y<LCD_HEIGHT; y++)
lcd_data(0x000000);
- lcd_sleep(0);
+ lcd_sleep(false);
}
-/* This is ugly hack. We drive lcd in bypass mode
- * where all writes goes directly to lcd controller.
- * This is suboptimal at best. IF module povides
- * FIFO, internal sram buffer, hardware scaller,
- * DMA signals, hardware alpha blending and more.
- * BUT the fact is that I have no idea how to use
- * this modes. Datasheet floating around is very
- * unclean in this regard and OF uses ackward
- * lcd update routines which are hard to understand.
- * Moreover OF sets some bits in IF module registers
- * which are referred as reseved in datasheet.
- */
-void lcd_update()
-{
- lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
-}
-
-
void lcd_update_rect(int x, int y, int width, int height)
{
int px = x, py = y;