diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2010-05-18 23:50:00 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2010-05-18 23:50:00 +0000 |
commit | 54c649697b3959d8f74888bd7ec9af0206f7670c (patch) | |
tree | f32061c0514b78d331eb7d9d4b623ae7cffea1f0 /firmware/target/arm | |
parent | 4c6164feced84c7d4a55ec8a5ee3ff398ffc7c53 (diff) | |
download | rockbox-54c649697b3959d8f74888bd7ec9af0206f7670c.tar.gz rockbox-54c649697b3959d8f74888bd7ec9af0206f7670c.zip |
Gigabeat S: Implement LCD contrast, invert and flip modes. Enhance LCD power management. Include init data but it's not needed yet (identical to Gigabeat F).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26154 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c | 183 | ||||
-rw-r--r-- | firmware/target/arm/imx31/spi-imx31.c | 6 | ||||
-rw-r--r-- | firmware/target/arm/imx31/spi-imx31.h | 3 |
3 files changed, 169 insertions, 23 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c index fd0aebe3a2..fbcd54059e 100644 --- a/firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c | |||
@@ -22,7 +22,10 @@ | |||
22 | #include "inttypes.h" | 22 | #include "inttypes.h" |
23 | 23 | ||
24 | #include "config.h" | 24 | #include "config.h" |
25 | #include "system.h" | ||
25 | #include "cpu.h" | 26 | #include "cpu.h" |
27 | #include "spi-imx31.h" | ||
28 | #include "mc13783.h" | ||
26 | #include "string.h" | 29 | #include "string.h" |
27 | #include "lcd.h" | 30 | #include "lcd.h" |
28 | #include "kernel.h" | 31 | #include "kernel.h" |
@@ -32,16 +35,117 @@ | |||
32 | #define MAIN_LCD_IDMAC_CHANNEL 14 | 35 | #define MAIN_LCD_IDMAC_CHANNEL 14 |
33 | #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)]) | 36 | #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)]) |
34 | 37 | ||
35 | static bool lcd_on = true; | ||
36 | static bool lcd_powered = true; | ||
37 | static unsigned lcd_yuv_options = 0; | ||
38 | |||
39 | /* Copies a rectangle from one framebuffer to another. Can be used in | 38 | /* Copies a rectangle from one framebuffer to another. Can be used in |
40 | single transfer mode with width = num pixels, and height = 1 which | 39 | single transfer mode with width = num pixels, and height = 1 which |
41 | allows a full-width rectangle to be copied more efficiently. */ | 40 | allows a full-width rectangle to be copied more efficiently. */ |
42 | extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src, | 41 | extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src, |
43 | int width, int height); | 42 | int width, int height); |
44 | 43 | ||
44 | static bool lcd_on = true; | ||
45 | static bool lcd_powered = true; | ||
46 | static unsigned lcd_yuv_options = 0; | ||
47 | |||
48 | #if 0 | ||
49 | /* Initialization data from OF bootloader. Identical to Gigabeat F/X. */ | ||
50 | static const unsigned char lcd_init_data[50] = | ||
51 | { | ||
52 | /* Reg Val */ | ||
53 | 0x0f, 0x01, | ||
54 | 0x09, 0x06, | ||
55 | 0x16, 0xa6, | ||
56 | 0x1e, 0x49, | ||
57 | 0x1f, 0x26, | ||
58 | 0x0b, 0x2f, /* Set contrast 0-63 */ | ||
59 | 0x0c, 0x2b, | ||
60 | 0x19, 0x5e, | ||
61 | 0x1a, 0x15, | ||
62 | 0x1b, 0x15, | ||
63 | 0x1d, 0x01, | ||
64 | 0x00, 0x03, | ||
65 | 0x01, 0x10, | ||
66 | 0x02, 0x0a, | ||
67 | 0x06, 0x04, /* Set the orientation 2=upside down, 4=normal */ | ||
68 | 0x08, 0x2e, | ||
69 | 0x24, 0x12, | ||
70 | 0x25, 0x3f, | ||
71 | 0x26, 0x0b, | ||
72 | 0x27, 0x00, | ||
73 | 0x28, 0x00, | ||
74 | 0x29, 0xf6, | ||
75 | 0x2a, 0x03, | ||
76 | 0x2b, 0x0a, | ||
77 | 0x04, 0x01, /* Display ON */ | ||
78 | }; | ||
79 | #endif | ||
80 | |||
81 | static const struct spi_node lcd_spi_node = | ||
82 | { | ||
83 | /* Original firmware settings for LCD panel commication */ | ||
84 | CSPI3_NUM, /* CSPI module 3 */ | ||
85 | CSPI_CONREG_CHIP_SELECT_SS1 | /* Chip select 1 */ | ||
86 | CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */ | ||
87 | CSPI_CONREG_DATA_RATE_DIV_16 | /* Clock = IPG_CLK/16 = 4,125,000Hz. */ | ||
88 | CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */ | ||
89 | CSPI_CONREG_SSPOL | /* SS active high */ | ||
90 | CSPI_CONREG_PHA | /* Phase 1 operation */ | ||
91 | CSPI_CONREG_POL | /* Active low polarity */ | ||
92 | CSPI_CONREG_MODE, /* Master mode */ | ||
93 | 0, /* SPI clock - no wait states */ | ||
94 | }; | ||
95 | |||
96 | static void lcd_write_reg(unsigned reg, unsigned val) | ||
97 | { | ||
98 | /* packet: |00|rr|01|vv| */ | ||
99 | uint32_t packet = ((reg & 0xff) << 16) | 0x0100 | (val & 0xff); | ||
100 | |||
101 | struct spi_transfer_desc xfer; | ||
102 | |||
103 | xfer.node = &lcd_spi_node; | ||
104 | xfer.txbuf = &packet; | ||
105 | xfer.rxbuf = NULL; | ||
106 | xfer.count = 1; | ||
107 | xfer.callback = NULL; | ||
108 | xfer.next = NULL; | ||
109 | |||
110 | if (spi_transfer(&xfer)) | ||
111 | { | ||
112 | /* Just busy wait; the interface is not used very much */ | ||
113 | while (!spi_transfer_complete(&xfer)); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | static void lcd_enable_interface(bool enable) | ||
118 | { | ||
119 | if (enable) | ||
120 | { | ||
121 | spi_enable_module(&lcd_spi_node); | ||
122 | } | ||
123 | else | ||
124 | { | ||
125 | spi_disable_module(&lcd_spi_node); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static void lcd_set_power(bool powered) | ||
130 | { | ||
131 | if (powered) | ||
132 | { | ||
133 | lcd_powered = false; | ||
134 | lcd_write_reg(0x04, 0x00); | ||
135 | lcd_enable_interface(false); | ||
136 | imx31_regclr32(&GPIO3_DR, (1 << 12)); | ||
137 | mc13783_clear(MC13783_REGULATOR_MODE1, MC13783_VCAMEN); | ||
138 | } | ||
139 | else | ||
140 | { | ||
141 | mc13783_set(MC13783_REGULATOR_MODE1, MC13783_VCAMEN); | ||
142 | imx31_regset32(&GPIO3_DR, (1 << 12)); | ||
143 | lcd_enable_interface(true); | ||
144 | lcd_write_reg(0x04, 0x01); | ||
145 | lcd_powered = true; | ||
146 | } | ||
147 | } | ||
148 | |||
45 | /* LCD init */ | 149 | /* LCD init */ |
46 | void lcd_init_device(void) | 150 | void lcd_init_device(void) |
47 | { | 151 | { |
@@ -50,8 +154,19 @@ void lcd_init_device(void) | |||
50 | /* Only do this once to avoid flicker */ | 154 | /* Only do this once to avoid flicker */ |
51 | memset(FRAME, 0x00, FRAME_SIZE); | 155 | memset(FRAME, 0x00, FRAME_SIZE); |
52 | #endif | 156 | #endif |
53 | IPU_IMA_ADDR = ((0x1 << 16) | (MAIN_LCD_IDMAC_CHANNEL << 4)) + (1 << 3); | 157 | IPU_IPU_IMA_ADDR = ((0x1 << 16) | (MAIN_LCD_IDMAC_CHANNEL << 4)) + (1 << 3); |
54 | IPU_IMA_DATA = FRAME_PHYS_ADDR; | 158 | IPU_IPU_IMA_DATA = FRAME_PHYS_ADDR; |
159 | |||
160 | lcd_enable_interface(true); | ||
161 | #ifdef HAVE_LCD_CONTRAST | ||
162 | lcd_set_contrast(DEFAULT_CONTRAST_SETTING); | ||
163 | #endif | ||
164 | #ifdef HAVE_LCD_INVERT | ||
165 | lcd_set_invert_display(false); | ||
166 | #endif | ||
167 | #ifdef HAVE_LCD_FLIP | ||
168 | lcd_set_flip(false); | ||
169 | #endif | ||
55 | } | 170 | } |
56 | 171 | ||
57 | /* Update a fraction of the display. */ | 172 | /* Update a fraction of the display. */ |
@@ -96,13 +211,14 @@ void lcd_update_rect(int x, int y, int width, int height) | |||
96 | 211 | ||
97 | void lcd_sleep(void) | 212 | void lcd_sleep(void) |
98 | { | 213 | { |
99 | if (lcd_powered) | 214 | if (!lcd_powered) |
100 | { | 215 | return; |
101 | lcd_enable(false); | 216 | |
102 | lcd_powered = false; | 217 | IPU_IDMAC_CHA_EN &= ~(1ul << MAIN_LCD_IDMAC_CHANNEL); |
103 | IPU_IDMAC_CHA_EN &= ~(1ul << MAIN_LCD_IDMAC_CHANNEL); | 218 | IPU_IPU_CONF &= ~IPU_IPU_CONF_ADC_EN; |
104 | _backlight_lcd_sleep(); | 219 | lcd_enable(false); |
105 | } | 220 | lcd_set_power(false); |
221 | _backlight_lcd_sleep(); | ||
106 | } | 222 | } |
107 | 223 | ||
108 | void lcd_enable(bool state) | 224 | void lcd_enable(bool state) |
@@ -112,9 +228,11 @@ void lcd_enable(bool state) | |||
112 | 228 | ||
113 | if (state) | 229 | if (state) |
114 | { | 230 | { |
231 | if (!lcd_powered) | ||
232 | lcd_set_power(true); | ||
233 | IPU_IPU_CONF |= IPU_IPU_CONF_ADC_EN; | ||
115 | IPU_IDMAC_CHA_EN |= 1ul << MAIN_LCD_IDMAC_CHANNEL; | 234 | IPU_IDMAC_CHA_EN |= 1ul << MAIN_LCD_IDMAC_CHANNEL; |
116 | sleep(HZ/50); | 235 | sleep(HZ/50); |
117 | lcd_powered = true; | ||
118 | lcd_on = true; | 236 | lcd_on = true; |
119 | lcd_update(); | 237 | lcd_update(); |
120 | send_event(LCD_EVENT_ACTIVATION, NULL); | 238 | send_event(LCD_EVENT_ACTIVATION, NULL); |
@@ -211,18 +329,37 @@ void lcd_blit_yuv(unsigned char * const src[3], | |||
211 | } | 329 | } |
212 | } | 330 | } |
213 | 331 | ||
214 | void lcd_set_contrast(int val) { | 332 | #ifdef HAVE_LCD_CONTRAST |
215 | (void) val; | 333 | void lcd_set_contrast(int val) |
216 | // TODO: | 334 | { |
335 | if (!lcd_on) | ||
336 | return; | ||
337 | |||
338 | lcd_write_reg(0x0b, val); | ||
217 | } | 339 | } |
218 | 340 | ||
219 | void lcd_set_invert_display(bool yesno) { | 341 | int lcd_default_contrast(void) |
220 | (void) yesno; | 342 | { |
221 | // TODO: | 343 | return DEFAULT_CONTRAST_SETTING; |
222 | } | 344 | } |
345 | #endif /* HAVE_LCD_CONTRAST */ | ||
223 | 346 | ||
224 | void lcd_set_flip(bool yesno) { | 347 | #ifdef HAVE_LCD_INVERT |
225 | (void) yesno; | 348 | void lcd_set_invert_display(bool yesno) |
226 | // TODO: | 349 | { |
350 | if (!lcd_on) | ||
351 | return; | ||
352 | |||
353 | lcd_write_reg(0x27, yesno ? 0x10 : 00); | ||
227 | } | 354 | } |
355 | #endif /* HAVE_LCD_INVERT */ | ||
228 | 356 | ||
357 | #ifdef HAVE_LCD_FLIP | ||
358 | void lcd_set_flip(bool yesno) | ||
359 | { | ||
360 | if (!lcd_on) | ||
361 | return; | ||
362 | |||
363 | lcd_write_reg(0x06, yesno ? 0x02 : 0x04); | ||
364 | } | ||
365 | #endif /* HAVE_LCD_FLIP */ | ||
diff --git a/firmware/target/arm/imx31/spi-imx31.c b/firmware/target/arm/imx31/spi-imx31.c index e6dddd65c1..e0187e4388 100644 --- a/firmware/target/arm/imx31/spi-imx31.c +++ b/firmware/target/arm/imx31/spi-imx31.c | |||
@@ -435,3 +435,9 @@ bool spi_transfer(struct spi_transfer_desc *xfer) | |||
435 | 435 | ||
436 | return retval; | 436 | return retval; |
437 | } | 437 | } |
438 | |||
439 | /* Returns 'true' if the descriptor is not busy */ | ||
440 | bool spi_transfer_complete(const struct spi_transfer_desc *xfer) | ||
441 | { | ||
442 | return xfer->next == NULL; | ||
443 | } | ||
diff --git a/firmware/target/arm/imx31/spi-imx31.h b/firmware/target/arm/imx31/spi-imx31.h index 71f9512103..35b7d514cf 100644 --- a/firmware/target/arm/imx31/spi-imx31.h +++ b/firmware/target/arm/imx31/spi-imx31.h | |||
@@ -83,4 +83,7 @@ void spi_disable_module(const struct spi_node *node); | |||
83 | /* Send and/or receive data on the specified node (asychronous) */ | 83 | /* Send and/or receive data on the specified node (asychronous) */ |
84 | bool spi_transfer(struct spi_transfer_desc *xfer); | 84 | bool spi_transfer(struct spi_transfer_desc *xfer); |
85 | 85 | ||
86 | /* Returns 'true' if the descriptor is not busy */ | ||
87 | bool spi_transfer_complete(const struct spi_transfer_desc *xfer); | ||
88 | |||
86 | #endif /* SPI_IMX31_H */ | 89 | #endif /* SPI_IMX31_H */ |