]>
Commit | Line | Data |
---|---|---|
607232e4 MV |
1 | /* |
2 | * SanDisk Sansa Fuze Plus board | |
3 | * | |
4 | * Copyright (C) 2013 Marek Vasut <marex@denx.de> | |
5 | * | |
6 | * Hardware investigation done by: | |
7 | * | |
8 | * Amaury Pouly <amaury.pouly@gmail.com> | |
9 | * | |
10 | * SPDX-License-Identifier: GPL-2.0+ | |
11 | */ | |
12 | ||
13 | #include <common.h> | |
14 | #include <errno.h> | |
15 | #include <asm/gpio.h> | |
16 | #include <asm/io.h> | |
17 | #include <asm/arch/iomux-mx23.h> | |
18 | #include <asm/arch/imx-regs.h> | |
19 | #include <asm/arch/clock.h> | |
20 | #include <asm/arch/sys_proto.h> | |
21 | ||
22 | DECLARE_GLOBAL_DATA_PTR; | |
23 | ||
24 | /* | |
25 | * Functions | |
26 | */ | |
27 | int board_early_init_f(void) | |
28 | { | |
29 | /* IO0 clock at 480MHz */ | |
30 | mxs_set_ioclk(MXC_IOCLK0, 480000); | |
31 | ||
32 | /* SSP0 clock at 96MHz */ | |
33 | mxs_set_sspclk(MXC_SSPCLK0, 96000, 0); | |
34 | ||
35 | return 0; | |
36 | } | |
37 | ||
38 | int dram_init(void) | |
39 | { | |
40 | return mxs_dram_init(); | |
41 | } | |
42 | ||
43 | #ifdef CONFIG_CMD_MMC | |
44 | static int xfi3_mmc_cd(int id) | |
45 | { | |
46 | switch (id) { | |
47 | case 0: | |
48 | /* The SSP_DETECT is inverted on this board. */ | |
49 | return gpio_get_value(MX23_PAD_SSP1_DETECT__GPIO_2_1); | |
50 | case 1: | |
51 | /* Internal eMMC always present */ | |
52 | return 1; | |
53 | default: | |
54 | return 0; | |
55 | } | |
56 | } | |
57 | ||
58 | int board_mmc_init(bd_t *bis) | |
59 | { | |
60 | int ret; | |
61 | ||
62 | /* MicroSD slot */ | |
63 | gpio_direction_input(MX23_PAD_SSP1_DETECT__GPIO_2_1); | |
64 | gpio_direction_output(MX23_PAD_GPMI_D08__GPIO_0_8, 0); | |
65 | ret = mxsmmc_initialize(bis, 0, NULL, xfi3_mmc_cd); | |
66 | if (ret) | |
67 | return ret; | |
68 | ||
69 | /* Internal eMMC */ | |
70 | gpio_direction_output(MX23_PAD_PWM3__GPIO_1_29, 0); | |
71 | ret = mxsmmc_initialize(bis, 1, NULL, xfi3_mmc_cd); | |
72 | ||
73 | return ret; | |
74 | } | |
75 | #endif | |
76 | ||
77 | #ifdef CONFIG_VIDEO_MXS | |
78 | #define MUX_CONFIG_LCD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL) | |
79 | const iomux_cfg_t iomux_lcd_gpio[] = { | |
80 | MX23_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_LCD, | |
81 | MX23_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_LCD, | |
82 | MX23_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_LCD, | |
83 | MX23_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_LCD, | |
84 | MX23_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_LCD, | |
85 | MX23_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_LCD, | |
86 | MX23_PAD_LCD_D06__GPIO_1_6 | MUX_CONFIG_LCD, | |
87 | MX23_PAD_LCD_D07__GPIO_1_7 | MUX_CONFIG_LCD, | |
88 | MX23_PAD_LCD_D08__GPIO_1_8 | MUX_CONFIG_LCD, | |
89 | MX23_PAD_LCD_D09__GPIO_1_9 | MUX_CONFIG_LCD, | |
90 | MX23_PAD_LCD_D10__GPIO_1_10 | MUX_CONFIG_LCD, | |
91 | MX23_PAD_LCD_D11__GPIO_1_11 | MUX_CONFIG_LCD, | |
92 | MX23_PAD_LCD_D12__GPIO_1_12 | MUX_CONFIG_LCD, | |
93 | MX23_PAD_LCD_D13__GPIO_1_13 | MUX_CONFIG_LCD, | |
94 | MX23_PAD_LCD_D14__GPIO_1_14 | MUX_CONFIG_LCD, | |
95 | MX23_PAD_LCD_D15__GPIO_1_15 | MUX_CONFIG_LCD, | |
96 | MX23_PAD_LCD_D16__GPIO_1_16 | MUX_CONFIG_LCD, | |
97 | MX23_PAD_LCD_D17__GPIO_1_17 | MUX_CONFIG_LCD, | |
98 | MX23_PAD_LCD_RESET__GPIO_1_18 | MUX_CONFIG_LCD, | |
99 | MX23_PAD_LCD_RS__GPIO_1_19 | MUX_CONFIG_LCD, | |
100 | MX23_PAD_LCD_WR__GPIO_1_20 | MUX_CONFIG_LCD, | |
101 | MX23_PAD_LCD_CS__GPIO_1_21 | MUX_CONFIG_LCD, | |
102 | MX23_PAD_LCD_ENABLE__GPIO_1_23 | MUX_CONFIG_LCD, | |
103 | }; | |
104 | ||
105 | const iomux_cfg_t iomux_lcd_lcd[] = { | |
106 | MX23_PAD_LCD_D00__LCD_D00 | MUX_CONFIG_LCD, | |
107 | MX23_PAD_LCD_D01__LCD_D01 | MUX_CONFIG_LCD, | |
108 | MX23_PAD_LCD_D02__LCD_D02 | MUX_CONFIG_LCD, | |
109 | MX23_PAD_LCD_D03__LCD_D03 | MUX_CONFIG_LCD, | |
110 | MX23_PAD_LCD_D04__LCD_D04 | MUX_CONFIG_LCD, | |
111 | MX23_PAD_LCD_D05__LCD_D05 | MUX_CONFIG_LCD, | |
112 | MX23_PAD_LCD_D06__LCD_D06 | MUX_CONFIG_LCD, | |
113 | MX23_PAD_LCD_D07__LCD_D07 | MUX_CONFIG_LCD, | |
114 | MX23_PAD_LCD_D08__LCD_D08 | MUX_CONFIG_LCD, | |
115 | MX23_PAD_LCD_D09__LCD_D09 | MUX_CONFIG_LCD, | |
116 | MX23_PAD_LCD_D10__LCD_D10 | MUX_CONFIG_LCD, | |
117 | MX23_PAD_LCD_D11__LCD_D11 | MUX_CONFIG_LCD, | |
118 | MX23_PAD_LCD_D12__LCD_D12 | MUX_CONFIG_LCD, | |
119 | MX23_PAD_LCD_D13__LCD_D13 | MUX_CONFIG_LCD, | |
120 | MX23_PAD_LCD_D14__LCD_D14 | MUX_CONFIG_LCD, | |
121 | MX23_PAD_LCD_D15__LCD_D15 | MUX_CONFIG_LCD, | |
122 | MX23_PAD_LCD_D16__LCD_D16 | MUX_CONFIG_LCD, | |
123 | MX23_PAD_LCD_D17__LCD_D17 | MUX_CONFIG_LCD, | |
124 | MX23_PAD_LCD_RESET__LCD_RESET | MUX_CONFIG_LCD, | |
125 | MX23_PAD_LCD_RS__LCD_RS | MUX_CONFIG_LCD, | |
126 | MX23_PAD_LCD_WR__LCD_WR | MUX_CONFIG_LCD, | |
127 | MX23_PAD_LCD_CS__LCD_CS | MUX_CONFIG_LCD, | |
128 | MX23_PAD_LCD_ENABLE__LCD_ENABLE | MUX_CONFIG_LCD, | |
129 | MX23_PAD_LCD_VSYNC__LCD_VSYNC | MUX_CONFIG_LCD, | |
130 | }; | |
131 | ||
132 | static int mxsfb_read_register(uint32_t reg, uint32_t *value) | |
133 | { | |
134 | iomux_cfg_t mux; | |
135 | uint32_t val = 0; | |
136 | int i; | |
137 | ||
138 | /* Mangle the register offset. */ | |
139 | reg = ((reg & 0xff) << 1) | (((reg >> 8) & 0xff) << 10); | |
140 | ||
141 | /* | |
142 | * The SmartLCD interface on MX233 can only do WRITE operation | |
143 | * via the LCDIF controller. Implement the READ operation by | |
144 | * fiddling with bits. | |
145 | */ | |
146 | mxs_iomux_setup_multiple_pads(iomux_lcd_gpio, | |
147 | ARRAY_SIZE(iomux_lcd_gpio)); | |
148 | ||
149 | gpio_direction_output(MX23_PAD_LCD_RS__GPIO_1_19, 1); | |
150 | gpio_direction_output(MX23_PAD_LCD_CS__GPIO_1_21, 1); | |
151 | gpio_direction_output(MX23_PAD_LCD_WR__GPIO_1_20, 1); | |
152 | gpio_direction_output(MX23_PAD_LCD_ENABLE__GPIO_1_23, 1); | |
153 | ||
154 | for (i = 0; i < 18; i++) { | |
155 | mux = MXS_IOMUX_PAD_NAKED(1, i, PAD_MUXSEL_GPIO); | |
156 | gpio_direction_output(mux, 0); | |
157 | } | |
158 | ||
159 | udelay(2); | |
160 | gpio_direction_output(MX23_PAD_LCD_RS__GPIO_1_19, 0); | |
161 | udelay(1); | |
162 | gpio_direction_output(MX23_PAD_LCD_CS__GPIO_1_21, 0); | |
163 | udelay(1); | |
164 | gpio_direction_output(MX23_PAD_LCD_WR__GPIO_1_20, 0); | |
165 | udelay(1); | |
166 | ||
167 | for (i = 0; i < 18; i++) { | |
168 | mux = MXS_IOMUX_PAD_NAKED(1, i, PAD_MUXSEL_GPIO); | |
169 | gpio_direction_output(mux, (reg >> i) & 1); | |
170 | } | |
171 | udelay(1); | |
172 | ||
173 | gpio_direction_output(MX23_PAD_LCD_WR__GPIO_1_20, 1); | |
174 | udelay(3); | |
175 | ||
176 | for (i = 0; i < 18; i++) { | |
177 | mux = MXS_IOMUX_PAD_NAKED(1, i, PAD_MUXSEL_GPIO); | |
178 | gpio_direction_input(mux); | |
179 | } | |
180 | udelay(2); | |
181 | ||
182 | gpio_direction_output(MX23_PAD_LCD_ENABLE__GPIO_1_23, 0); | |
183 | udelay(1); | |
184 | gpio_direction_output(MX23_PAD_LCD_RS__GPIO_1_19, 1); | |
185 | udelay(1); | |
186 | gpio_direction_output(MX23_PAD_LCD_ENABLE__GPIO_1_23, 1); | |
187 | udelay(3); | |
188 | gpio_direction_output(MX23_PAD_LCD_ENABLE__GPIO_1_23, 0); | |
189 | udelay(2); | |
190 | ||
191 | for (i = 0; i < 18; i++) { | |
192 | mux = MXS_IOMUX_PAD_NAKED(1, i, PAD_MUXSEL_GPIO); | |
193 | val |= !!gpio_get_value(mux) << i; | |
194 | } | |
195 | udelay(1); | |
196 | ||
197 | gpio_direction_output(MX23_PAD_LCD_ENABLE__GPIO_1_23, 1); | |
198 | udelay(1); | |
199 | gpio_direction_output(MX23_PAD_LCD_CS__GPIO_1_21, 1); | |
200 | udelay(1); | |
201 | ||
202 | mxs_iomux_setup_multiple_pads(iomux_lcd_lcd, | |
203 | ARRAY_SIZE(iomux_lcd_lcd)); | |
204 | ||
205 | /* Demangle the register value. */ | |
206 | *value = ((val >> 1) & 0xff) | ((val >> 2) & 0xff00); | |
207 | ||
208 | writel(val, 0x2000); | |
209 | return 0; | |
210 | } | |
211 | ||
212 | static int mxsfb_write_byte(uint32_t payload, const unsigned int data) | |
213 | { | |
214 | struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)MXS_LCDIF_BASE; | |
215 | const unsigned int timeout = 0x10000; | |
216 | ||
217 | /* What is going on here I do not know. FIXME */ | |
218 | payload = ((payload & 0xff) << 1) | (((payload >> 8) & 0xff) << 10); | |
219 | ||
220 | if (mxs_wait_mask_clr(®s->hw_lcdif_ctrl_reg, LCDIF_CTRL_RUN, | |
221 | timeout)) | |
222 | return -ETIMEDOUT; | |
223 | ||
224 | writel((1 << LCDIF_TRANSFER_COUNT_V_COUNT_OFFSET) | | |
225 | (1 << LCDIF_TRANSFER_COUNT_H_COUNT_OFFSET), | |
226 | ®s->hw_lcdif_transfer_count); | |
227 | ||
228 | writel(LCDIF_CTRL_DATA_SELECT | LCDIF_CTRL_RUN, | |
229 | ®s->hw_lcdif_ctrl_clr); | |
230 | ||
231 | if (data) | |
232 | writel(LCDIF_CTRL_DATA_SELECT, ®s->hw_lcdif_ctrl_set); | |
233 | ||
234 | writel(LCDIF_CTRL_RUN, ®s->hw_lcdif_ctrl_set); | |
235 | ||
236 | if (mxs_wait_mask_clr(®s->hw_lcdif_lcdif_stat_reg, 1 << 29, | |
237 | timeout)) | |
238 | return -ETIMEDOUT; | |
239 | ||
240 | writel(payload, ®s->hw_lcdif_data); | |
241 | return mxs_wait_mask_clr(®s->hw_lcdif_ctrl_reg, LCDIF_CTRL_RUN, | |
242 | timeout); | |
243 | } | |
244 | ||
245 | static void mxsfb_write_register(uint32_t reg, uint32_t data) | |
246 | { | |
247 | mxsfb_write_byte(reg, 0); | |
248 | mxsfb_write_byte(data, 1); | |
249 | } | |
250 | ||
251 | static const struct { | |
252 | uint8_t reg; | |
253 | uint8_t delay; | |
254 | uint16_t val; | |
255 | } lcd_regs[] = { | |
256 | { 0xe5, 0 , 0x78f0 }, | |
257 | { 0xe3, 0 , 0x3008 }, | |
258 | { 0xe7, 0 , 0x0012 }, | |
259 | { 0xef, 0 , 0x1231 }, | |
260 | { 0x00, 0 , 0x0001 }, | |
261 | { 0x01, 0 , 0x0100 }, | |
262 | { 0x02, 0 , 0x0700 }, | |
263 | { 0x03, 0 , 0x1030 }, | |
264 | { 0x04, 0 , 0x0000 }, | |
265 | { 0x08, 0 , 0x0207 }, | |
266 | { 0x09, 0 , 0x0000 }, | |
267 | { 0x0a, 0 , 0x0000 }, | |
268 | { 0x0c, 0 , 0x0000 }, | |
269 | { 0x0d, 0 , 0x0000 }, | |
270 | { 0x0f, 0 , 0x0000 }, | |
271 | { 0x10, 0 , 0x0000 }, | |
272 | { 0x11, 0 , 0x0007 }, | |
273 | { 0x12, 0 , 0x0000 }, | |
274 | { 0x13, 20 , 0x0000 }, | |
275 | /* Wait 20 mS here. */ | |
276 | { 0x10, 0 , 0x1290 }, | |
277 | { 0x11, 50 , 0x0007 }, | |
278 | /* Wait 50 mS here. */ | |
279 | { 0x12, 50 , 0x0019 }, | |
280 | /* Wait 50 mS here. */ | |
281 | { 0x13, 0 , 0x1700 }, | |
282 | { 0x29, 50 , 0x0014 }, | |
283 | /* Wait 50 mS here. */ | |
284 | { 0x20, 0 , 0x0000 }, | |
285 | { 0x21, 0 , 0x0000 }, | |
286 | { 0x30, 0 , 0x0504 }, | |
287 | { 0x31, 0 , 0x0007 }, | |
288 | { 0x32, 0 , 0x0006 }, | |
289 | { 0x35, 0 , 0x0106 }, | |
290 | { 0x36, 0 , 0x0202 }, | |
291 | { 0x37, 0 , 0x0504 }, | |
292 | { 0x38, 0 , 0x0500 }, | |
293 | { 0x39, 0 , 0x0706 }, | |
294 | { 0x3c, 0 , 0x0204 }, | |
295 | { 0x3d, 0 , 0x0202 }, | |
296 | { 0x50, 0 , 0x0000 }, | |
297 | { 0x51, 0 , 0x00ef }, | |
298 | { 0x52, 0 , 0x0000 }, | |
299 | { 0x53, 0 , 0x013f }, | |
300 | { 0x60, 0 , 0xa700 }, | |
301 | { 0x61, 0 , 0x0001 }, | |
302 | { 0x6a, 0 , 0x0000 }, | |
303 | { 0x2b, 50 , 0x000d }, | |
304 | /* Wait 50 mS here. */ | |
305 | { 0x90, 0 , 0x0011 }, | |
306 | { 0x92, 0 , 0x0600 }, | |
307 | { 0x93, 0 , 0x0003 }, | |
308 | { 0x95, 0 , 0x0110 }, | |
309 | { 0x97, 0 , 0x0000 }, | |
310 | { 0x98, 0 , 0x0000 }, | |
311 | { 0x07, 0 , 0x0173 }, | |
312 | }; | |
313 | ||
314 | void board_mxsfb_system_setup(void) | |
315 | { | |
316 | struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)MXS_LCDIF_BASE; | |
317 | uint32_t id; | |
318 | int i; | |
319 | ||
320 | /* Switch the LCDIF into System-Mode */ | |
321 | writel(LCDIF_CTRL_LCDIF_MASTER | LCDIF_CTRL_DOTCLK_MODE | | |
322 | LCDIF_CTRL_BYPASS_COUNT, ®s->hw_lcdif_ctrl_clr); | |
323 | ||
324 | /* To program the LCD, switch to 18bit bus + 18bit data. */ | |
325 | clrsetbits_le32(®s->hw_lcdif_ctrl, | |
326 | LCDIF_CTRL_WORD_LENGTH_MASK | LCDIF_CTRL_LCD_DATABUS_WIDTH_MASK, | |
327 | LCDIF_CTRL_WORD_LENGTH_18BIT | | |
328 | LCDIF_CTRL_LCD_DATABUS_WIDTH_18BIT); | |
329 | ||
330 | mxsfb_read_register(0, &id); | |
331 | writel(id, 0x2004); | |
332 | ||
333 | /* Restart the SmartLCD controller */ | |
334 | mdelay(50); | |
335 | writel(1, ®s->hw_lcdif_ctrl1_set); | |
336 | mdelay(50); | |
337 | writel(1, ®s->hw_lcdif_ctrl1_clr); | |
338 | mdelay(50); | |
339 | writel(1, ®s->hw_lcdif_ctrl1_set); | |
340 | mdelay(50); | |
341 | ||
342 | /* Program the SmartLCD controller */ | |
343 | writel(LCDIF_CTRL1_RECOVER_ON_UNDERFLOW, ®s->hw_lcdif_ctrl1_set); | |
344 | ||
345 | writel((0x02 << LCDIF_TIMING_CMD_HOLD_OFFSET) | | |
346 | (0x02 << LCDIF_TIMING_CMD_SETUP_OFFSET) | | |
347 | (0x02 << LCDIF_TIMING_DATA_HOLD_OFFSET) | | |
348 | (0x01 << LCDIF_TIMING_DATA_SETUP_OFFSET), | |
349 | ®s->hw_lcdif_timing); | |
350 | ||
351 | /* | |
352 | * ILI9325 init and configuration sequence. | |
353 | */ | |
354 | for (i = 0; i < ARRAY_SIZE(lcd_regs); i++) { | |
355 | mxsfb_write_register(lcd_regs[i].reg, lcd_regs[i].val); | |
356 | if (lcd_regs[i].delay) | |
357 | mdelay(lcd_regs[i].delay); | |
358 | } | |
359 | /* Turn on Framebuffer Upload Mode */ | |
360 | mxsfb_write_byte(0x22, 0); | |
361 | ||
362 | writel(LCDIF_CTRL_LCDIF_MASTER | LCDIF_CTRL_DATA_SELECT, | |
363 | ®s->hw_lcdif_ctrl_set); | |
364 | ||
365 | /* Operate the framebuffer in 16bit mode. */ | |
366 | clrsetbits_le32(®s->hw_lcdif_ctrl, | |
367 | LCDIF_CTRL_WORD_LENGTH_MASK | LCDIF_CTRL_LCD_DATABUS_WIDTH_MASK, | |
368 | LCDIF_CTRL_WORD_LENGTH_16BIT | | |
369 | LCDIF_CTRL_LCD_DATABUS_WIDTH_18BIT); | |
370 | } | |
371 | #endif | |
372 | ||
373 | int board_init(void) | |
374 | { | |
375 | /* Adress of boot parameters */ | |
376 | gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; | |
377 | ||
378 | /* Turn on PWM backlight */ | |
379 | gpio_direction_output(MX23_PAD_PWM2__GPIO_1_28, 1); | |
380 | ||
381 | return 0; | |
382 | } | |
383 | ||
384 | int board_eth_init(bd_t *bis) | |
385 | { | |
386 | usb_eth_initialize(bis); | |
387 | return 0; | |
388 | } |