summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c183
-rw-r--r--firmware/target/arm/imx31/spi-imx31.c6
-rw-r--r--firmware/target/arm/imx31/spi-imx31.h3
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
35static bool lcd_on = true;
36static bool lcd_powered = true;
37static 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. */
42extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src, 41extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src,
43 int width, int height); 42 int width, int height);
44 43
44static bool lcd_on = true;
45static bool lcd_powered = true;
46static unsigned lcd_yuv_options = 0;
47
48#if 0
49/* Initialization data from OF bootloader. Identical to Gigabeat F/X. */
50static 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
81static 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
96static 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
117static 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
129static 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 */
46void lcd_init_device(void) 150void 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
97void lcd_sleep(void) 212void 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
108void lcd_enable(bool state) 224void 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
214void lcd_set_contrast(int val) { 332#ifdef HAVE_LCD_CONTRAST
215 (void) val; 333void 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
219void lcd_set_invert_display(bool yesno) { 341int lcd_default_contrast(void)
220 (void) yesno; 342{
221 // TODO: 343 return DEFAULT_CONTRAST_SETTING;
222} 344}
345#endif /* HAVE_LCD_CONTRAST */
223 346
224void lcd_set_flip(bool yesno) { 347#ifdef HAVE_LCD_INVERT
225 (void) yesno; 348void 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
358void 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 */
440bool 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) */
84bool spi_transfer(struct spi_transfer_desc *xfer); 84bool spi_transfer(struct spi_transfer_desc *xfer);
85 85
86/* Returns 'true' if the descriptor is not busy */
87bool spi_transfer_complete(const struct spi_transfer_desc *xfer);
88
86#endif /* SPI_IMX31_H */ 89#endif /* SPI_IMX31_H */