]>
Commit | Line | Data |
---|---|---|
9e40808c MK |
1 | /* |
2 | * Copyright (C) 2010 Samsung Electronics | |
3 | * Minkyu Kang <mk7.kang@samsung.com> | |
4 | * Kyungmin Park <kyungmin.park@samsung.com> | |
5 | * | |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
9e40808c MK |
7 | */ |
8 | ||
9 | #include <common.h> | |
ff0fedd5 | 10 | #include <spi.h> |
d984b9f8 | 11 | #include <lcd.h> |
9e40808c | 12 | #include <asm/io.h> |
ff0fedd5 | 13 | #include <asm/gpio.h> |
9e40808c | 14 | #include <asm/arch/adc.h> |
ea7991b8 | 15 | #include <asm/arch/pinmux.h> |
11a44798 | 16 | #include <asm/arch/watchdog.h> |
d984b9f8 | 17 | #include <ld9040.h> |
c7336815 | 18 | #include <power/pmic.h> |
3f41ffe4 | 19 | #include <usb.h> |
5d5716ee | 20 | #include <usb/dwc2_udc.h> |
ddc7e541 | 21 | #include <asm/arch/cpu.h> |
c7336815 | 22 | #include <power/max8998_pmic.h> |
3f41ffe4 | 23 | #include <libtizen.h> |
82b0a055 | 24 | #include <samsung/misc.h> |
3f41ffe4 | 25 | #include <usb_mass_storage.h> |
c62db35d | 26 | #include <asm/mach-types.h> |
9e40808c MK |
27 | |
28 | DECLARE_GLOBAL_DATA_PTR; | |
29 | ||
9e40808c | 30 | unsigned int board_rev; |
816d8b50 | 31 | static int init_pmic_lcd(void); |
9e40808c MK |
32 | |
33 | u32 get_board_rev(void) | |
34 | { | |
35 | return board_rev; | |
36 | } | |
37 | ||
816d8b50 | 38 | int exynos_power_init(void) |
9e40808c | 39 | { |
816d8b50 | 40 | return init_pmic_lcd(); |
9e40808c MK |
41 | } |
42 | ||
816d8b50 | 43 | static int get_hwrev(void) |
f5a7004c | 44 | { |
816d8b50 | 45 | return board_rev & 0xFF; |
f5a7004c | 46 | } |
9e40808c | 47 | |
9e40808c MK |
48 | static unsigned short get_adc_value(int channel) |
49 | { | |
50 | struct s5p_adc *adc = (struct s5p_adc *)samsung_get_base_adc(); | |
51 | unsigned short ret = 0; | |
52 | unsigned int reg; | |
53 | unsigned int loop = 0; | |
54 | ||
55 | writel(channel & 0xF, &adc->adcmux); | |
56 | writel((1 << 14) | (49 << 6), &adc->adccon); | |
57 | writel(1000 & 0xffff, &adc->adcdly); | |
58 | writel(readl(&adc->adccon) | (1 << 16), &adc->adccon); /* 12 bit */ | |
59 | udelay(10); | |
60 | writel(readl(&adc->adccon) | (1 << 0), &adc->adccon); /* Enable */ | |
61 | udelay(10); | |
62 | ||
63 | do { | |
64 | udelay(1); | |
65 | reg = readl(&adc->adccon); | |
66 | } while (!(reg & (1 << 15)) && (loop++ < 1000)); | |
67 | ||
68 | ret = readl(&adc->adcdat0) & 0xFFF; | |
69 | ||
70 | return ret; | |
71 | } | |
72 | ||
4d86bf08 ŁM |
73 | static int adc_power_control(int on) |
74 | { | |
816d8b50 | 75 | struct udevice *dev; |
4d86bf08 | 76 | int ret; |
816d8b50 | 77 | u8 reg; |
4d86bf08 | 78 | |
816d8b50 JC |
79 | ret = pmic_get("max8998-pmic", &dev); |
80 | if (ret) { | |
81 | puts("Failed to get MAX8998!\n"); | |
82 | return ret; | |
83 | } | |
4d86bf08 | 84 | |
816d8b50 JC |
85 | reg = pmic_reg_read(dev, MAX8998_REG_ONOFF1); |
86 | if (on) | |
87 | reg |= MAX8998_LDO4; | |
88 | else | |
89 | reg &= ~MAX8998_LDO4; | |
90 | ||
91 | ret = pmic_reg_write(dev, MAX8998_REG_ONOFF1, reg); | |
92 | if (ret) { | |
93 | puts("MAX8998 LDO setting error\n"); | |
94 | return -EINVAL; | |
95 | } | |
4d86bf08 | 96 | |
fc47cf9d | 97 | return 0; |
4d86bf08 ŁM |
98 | } |
99 | ||
9e40808c MK |
100 | static unsigned int get_hw_revision(void) |
101 | { | |
102 | int hwrev, mode0, mode1; | |
103 | ||
4d86bf08 ŁM |
104 | adc_power_control(1); |
105 | ||
9e40808c MK |
106 | mode0 = get_adc_value(1); /* HWREV_MODE0 */ |
107 | mode1 = get_adc_value(2); /* HWREV_MODE1 */ | |
108 | ||
109 | /* | |
110 | * XXX Always set the default hwrev as the latest board | |
111 | * ADC = (voltage) / 3.3 * 4096 | |
112 | */ | |
113 | hwrev = 3; | |
114 | ||
115 | #define IS_RANGE(x, min, max) ((x) > (min) && (x) < (max)) | |
116 | if (IS_RANGE(mode0, 80, 200) && IS_RANGE(mode1, 80, 200)) | |
117 | hwrev = 0x0; /* 0.01V 0.01V */ | |
118 | if (IS_RANGE(mode0, 750, 1000) && IS_RANGE(mode1, 80, 200)) | |
119 | hwrev = 0x1; /* 610mV 0.01V */ | |
120 | if (IS_RANGE(mode0, 1300, 1700) && IS_RANGE(mode1, 80, 200)) | |
121 | hwrev = 0x2; /* 1.16V 0.01V */ | |
122 | if (IS_RANGE(mode0, 2000, 2400) && IS_RANGE(mode1, 80, 200)) | |
123 | hwrev = 0x3; /* 1.79V 0.01V */ | |
124 | #undef IS_RANGE | |
125 | ||
126 | debug("mode0: %d, mode1: %d, hwrev 0x%x\n", mode0, mode1, hwrev); | |
127 | ||
4d86bf08 ŁM |
128 | adc_power_control(0); |
129 | ||
9e40808c MK |
130 | return hwrev; |
131 | } | |
132 | ||
133 | static void check_hw_revision(void) | |
134 | { | |
135 | int hwrev; | |
136 | ||
137 | hwrev = get_hw_revision(); | |
138 | ||
139 | board_rev |= hwrev; | |
140 | } | |
141 | ||
ddc7e541 ŁM |
142 | #ifdef CONFIG_USB_GADGET |
143 | static int s5pc210_phy_control(int on) | |
144 | { | |
816d8b50 JC |
145 | struct udevice *dev; |
146 | int ret; | |
147 | u8 reg; | |
ddc7e541 | 148 | |
816d8b50 JC |
149 | ret = pmic_get("max8998-pmic", &dev); |
150 | if (ret) { | |
151 | puts("Failed to get MAX8998!\n"); | |
152 | return ret; | |
153 | } | |
ddc7e541 ŁM |
154 | |
155 | if (on) { | |
816d8b50 JC |
156 | reg = pmic_reg_read(dev, MAX8998_REG_BUCK_ACTIVE_DISCHARGE3); |
157 | reg |= MAX8998_SAFEOUT1; | |
158 | ret |= pmic_reg_write(dev, | |
159 | MAX8998_REG_BUCK_ACTIVE_DISCHARGE3, reg); | |
160 | ||
161 | reg = pmic_reg_read(dev, MAX8998_REG_ONOFF1); | |
162 | reg |= MAX8998_LDO3; | |
163 | ret |= pmic_reg_write(dev, MAX8998_REG_ONOFF1, reg); | |
164 | ||
165 | reg = pmic_reg_read(dev, MAX8998_REG_ONOFF2); | |
166 | reg |= MAX8998_LDO8; | |
167 | ret |= pmic_reg_write(dev, MAX8998_REG_ONOFF2, reg); | |
ddc7e541 ŁM |
168 | |
169 | } else { | |
816d8b50 JC |
170 | reg = pmic_reg_read(dev, MAX8998_REG_ONOFF2); |
171 | reg &= ~MAX8998_LDO8; | |
172 | ret |= pmic_reg_write(dev, MAX8998_REG_ONOFF2, reg); | |
173 | ||
174 | reg = pmic_reg_read(dev, MAX8998_REG_ONOFF1); | |
175 | reg &= ~MAX8998_LDO3; | |
176 | ret |= pmic_reg_write(dev, MAX8998_REG_ONOFF1, reg); | |
177 | ||
178 | reg = pmic_reg_read(dev, MAX8998_REG_BUCK_ACTIVE_DISCHARGE3); | |
179 | reg &= ~MAX8998_SAFEOUT1; | |
180 | ret |= pmic_reg_write(dev, | |
181 | MAX8998_REG_BUCK_ACTIVE_DISCHARGE3, reg); | |
ddc7e541 ŁM |
182 | } |
183 | ||
184 | if (ret) { | |
185 | puts("MAX8998 LDO setting error!\n"); | |
816d8b50 | 186 | return -EINVAL; |
ddc7e541 | 187 | } |
816d8b50 | 188 | |
ddc7e541 ŁM |
189 | return 0; |
190 | } | |
191 | ||
c0982871 | 192 | struct dwc2_plat_otg_data s5pc210_otg_data = { |
ddc7e541 ŁM |
193 | .phy_control = s5pc210_phy_control, |
194 | .regs_phy = EXYNOS4_USBPHY_BASE, | |
195 | .regs_otg = EXYNOS4_USBOTG_BASE, | |
196 | .usb_phy_ctrl = EXYNOS4_USBPHY_CONTROL, | |
197 | .usb_flags = PHY0_SLEEP, | |
198 | }; | |
199 | #endif | |
11a44798 | 200 | |
3f41ffe4 PW |
201 | int board_usb_init(int index, enum usb_init_type init) |
202 | { | |
203 | debug("USB_udc_probe\n"); | |
a4bb9b36 | 204 | return dwc2_udc_probe(&s5pc210_otg_data); |
3f41ffe4 PW |
205 | } |
206 | ||
3f41ffe4 | 207 | int exynos_early_init_f(void) |
11a44798 PW |
208 | { |
209 | wdt_stop(); | |
210 | ||
211 | return 0; | |
212 | } | |
ff0fedd5 | 213 | |
816d8b50 | 214 | static int init_pmic_lcd(void) |
d984b9f8 | 215 | { |
816d8b50 | 216 | struct udevice *dev; |
d984b9f8 PW |
217 | unsigned char val; |
218 | int ret = 0; | |
219 | ||
816d8b50 JC |
220 | ret = pmic_get("max8998-pmic", &dev); |
221 | if (ret) { | |
222 | puts("Failed to get MAX8998 for init_pmic_lcd()!\n"); | |
223 | return ret; | |
224 | } | |
d984b9f8 PW |
225 | |
226 | /* LDO7 1.8V */ | |
227 | val = 0x02; /* (1800 - 1600) / 100; */ | |
816d8b50 | 228 | ret |= pmic_reg_write(dev, MAX8998_REG_LDO7, val); |
d984b9f8 PW |
229 | |
230 | /* LDO17 3.0V */ | |
231 | val = 0xe; /* (3000 - 1600) / 100; */ | |
816d8b50 | 232 | ret |= pmic_reg_write(dev, MAX8998_REG_LDO17, val); |
d984b9f8 PW |
233 | |
234 | /* Disable unneeded regulators */ | |
235 | /* | |
236 | * ONOFF1 | |
237 | * Buck1 ON, Buck2 OFF, Buck3 ON, Buck4 ON | |
238 | * LDO2 ON, LDO3 OFF, LDO4 OFF, LDO5 ON | |
239 | */ | |
240 | val = 0xB9; | |
816d8b50 | 241 | ret |= pmic_reg_write(dev, MAX8998_REG_ONOFF1, val); |
d984b9f8 PW |
242 | |
243 | /* ONOFF2 | |
244 | * LDO6 OFF, LDO7 ON, LDO8 OFF, LDO9 ON, | |
245 | * LDO10 OFF, LDO11 OFF, LDO12 OFF, LDO13 OFF | |
246 | */ | |
247 | val = 0x50; | |
816d8b50 | 248 | ret |= pmic_reg_write(dev, MAX8998_REG_ONOFF2, val); |
d984b9f8 PW |
249 | |
250 | /* ONOFF3 | |
251 | * LDO14 OFF, LDO15 OFF, LGO16 OFF, LDO17 OFF | |
252 | * EPWRHOLD OFF, EBATTMON OFF, ELBCNFG2 OFF, ELBCNFG1 OFF | |
253 | */ | |
254 | val = 0x00; | |
816d8b50 | 255 | ret |= pmic_reg_write(dev, MAX8998_REG_ONOFF3, val); |
d984b9f8 | 256 | |
816d8b50 | 257 | if (ret) { |
d984b9f8 | 258 | puts("LCD pmic initialisation error!\n"); |
816d8b50 JC |
259 | return -EINVAL; |
260 | } | |
261 | ||
262 | return 0; | |
d984b9f8 PW |
263 | } |
264 | ||
29fd5704 | 265 | void exynos_cfg_lcd_gpio(void) |
d984b9f8 PW |
266 | { |
267 | unsigned int i, f3_end = 4; | |
268 | ||
269 | for (i = 0; i < 8; i++) { | |
270 | /* set GPF0,1,2[0:7] for RGB Interface and Data lines (32bit) */ | |
f6ae1ca0 AS |
271 | gpio_cfg_pin(EXYNOS4_GPIO_F00 + i, S5P_GPIO_FUNC(2)); |
272 | gpio_cfg_pin(EXYNOS4_GPIO_F10 + i, S5P_GPIO_FUNC(2)); | |
273 | gpio_cfg_pin(EXYNOS4_GPIO_F20 + i, S5P_GPIO_FUNC(2)); | |
d984b9f8 | 274 | /* pull-up/down disable */ |
f6ae1ca0 AS |
275 | gpio_set_pull(EXYNOS4_GPIO_F00 + i, S5P_GPIO_PULL_NONE); |
276 | gpio_set_pull(EXYNOS4_GPIO_F10 + i, S5P_GPIO_PULL_NONE); | |
277 | gpio_set_pull(EXYNOS4_GPIO_F20 + i, S5P_GPIO_PULL_NONE); | |
d984b9f8 PW |
278 | |
279 | /* drive strength to max (24bit) */ | |
f6ae1ca0 AS |
280 | gpio_set_drv(EXYNOS4_GPIO_F00 + i, S5P_GPIO_DRV_4X); |
281 | gpio_set_rate(EXYNOS4_GPIO_F00 + i, S5P_GPIO_DRV_SLOW); | |
282 | gpio_set_drv(EXYNOS4_GPIO_F10 + i, S5P_GPIO_DRV_4X); | |
283 | gpio_set_rate(EXYNOS4_GPIO_F10 + i, S5P_GPIO_DRV_SLOW); | |
284 | gpio_set_drv(EXYNOS4_GPIO_F20 + i, S5P_GPIO_DRV_4X); | |
285 | gpio_set_rate(EXYNOS4_GPIO_F00 + i, S5P_GPIO_DRV_SLOW); | |
d984b9f8 PW |
286 | } |
287 | ||
f6ae1ca0 | 288 | for (i = EXYNOS4_GPIO_F30; i < (EXYNOS4_GPIO_F30 + f3_end); i++) { |
d984b9f8 | 289 | /* set GPF3[0:3] for RGB Interface and Data lines (32bit) */ |
f6ae1ca0 | 290 | gpio_cfg_pin(i, S5P_GPIO_FUNC(2)); |
d984b9f8 | 291 | /* pull-up/down disable */ |
f6ae1ca0 | 292 | gpio_set_pull(i, S5P_GPIO_PULL_NONE); |
d984b9f8 | 293 | /* drive strength to max (24bit) */ |
f6ae1ca0 AS |
294 | gpio_set_drv(i, S5P_GPIO_DRV_4X); |
295 | gpio_set_rate(i, S5P_GPIO_DRV_SLOW); | |
d984b9f8 PW |
296 | } |
297 | ||
298 | /* gpio pad configuration for LCD reset. */ | |
7f196101 | 299 | gpio_request(EXYNOS4_GPIO_Y45, "lcd_reset"); |
f6ae1ca0 | 300 | gpio_cfg_pin(EXYNOS4_GPIO_Y45, S5P_GPIO_OUTPUT); |
d984b9f8 PW |
301 | } |
302 | ||
3f41ffe4 PW |
303 | int mipi_power(void) |
304 | { | |
305 | return 0; | |
306 | } | |
307 | ||
29fd5704 | 308 | void exynos_reset_lcd(void) |
d984b9f8 | 309 | { |
f6ae1ca0 | 310 | gpio_set_value(EXYNOS4_GPIO_Y45, 1); |
d984b9f8 | 311 | udelay(10000); |
f6ae1ca0 | 312 | gpio_set_value(EXYNOS4_GPIO_Y45, 0); |
d984b9f8 | 313 | udelay(10000); |
f6ae1ca0 | 314 | gpio_set_value(EXYNOS4_GPIO_Y45, 1); |
d984b9f8 PW |
315 | udelay(100); |
316 | } | |
317 | ||
29fd5704 | 318 | void exynos_lcd_power_on(void) |
d984b9f8 | 319 | { |
816d8b50 JC |
320 | struct udevice *dev; |
321 | int ret; | |
322 | u8 reg; | |
d984b9f8 | 323 | |
816d8b50 JC |
324 | ret = pmic_get("max8998-pmic", &dev); |
325 | if (ret) { | |
326 | puts("Failed to get MAX8998!\n"); | |
fbef8e6e | 327 | return; |
816d8b50 | 328 | } |
fbef8e6e | 329 | |
816d8b50 JC |
330 | reg = pmic_reg_read(dev, MAX8998_REG_ONOFF3); |
331 | reg |= MAX8998_LDO17; | |
332 | ret = pmic_reg_write(dev, MAX8998_REG_ONOFF3, reg); | |
333 | if (ret) { | |
334 | puts("MAX8998 LDO setting error\n"); | |
d984b9f8 | 335 | return; |
816d8b50 | 336 | } |
d984b9f8 | 337 | |
816d8b50 JC |
338 | reg = pmic_reg_read(dev, MAX8998_REG_ONOFF2); |
339 | reg |= MAX8998_LDO7; | |
340 | ret = pmic_reg_write(dev, MAX8998_REG_ONOFF2, reg); | |
341 | if (ret) { | |
342 | puts("MAX8998 LDO setting error\n"); | |
343 | return; | |
344 | } | |
d984b9f8 PW |
345 | } |
346 | ||
29fd5704 AK |
347 | void exynos_cfg_ldo(void) |
348 | { | |
349 | ld9040_cfg_ldo(); | |
350 | } | |
351 | ||
352 | void exynos_enable_ldo(unsigned int onoff) | |
353 | { | |
354 | ld9040_enable_ldo(onoff); | |
355 | } | |
356 | ||
3f41ffe4 | 357 | int exynos_init(void) |
ff0fedd5 | 358 | { |
ff0fedd5 | 359 | gd->bd->bi_arch_number = MACH_TYPE_UNIVERSAL_C210; |
3f41ffe4 PW |
360 | |
361 | switch (get_hwrev()) { | |
362 | case 0: | |
363 | /* | |
364 | * Set the low to enable LDO_EN | |
365 | * But when you use the test board for eMMC booting | |
366 | * you should set it HIGH since it removes the inverter | |
367 | */ | |
368 | /* MASSMEMORY_EN: XMDMDATA_6: GPE3[6] */ | |
7f196101 | 369 | gpio_request(EXYNOS4_GPIO_E36, "ldo_en"); |
f6ae1ca0 | 370 | gpio_direction_output(EXYNOS4_GPIO_E36, 0); |
3f41ffe4 PW |
371 | break; |
372 | default: | |
373 | /* | |
374 | * Default reset state is High and there's no inverter | |
375 | * But set it as HIGH to ensure | |
376 | */ | |
377 | /* MASSMEMORY_EN: XMDMADDR_3: GPE1[3] */ | |
7f196101 | 378 | gpio_request(EXYNOS4_GPIO_E13, "massmemory_en"); |
f6ae1ca0 | 379 | gpio_direction_output(EXYNOS4_GPIO_E13, 1); |
3f41ffe4 PW |
380 | break; |
381 | } | |
ff0fedd5 | 382 | |
ff0fedd5 PW |
383 | check_hw_revision(); |
384 | printf("HW Revision:\t0x%x\n", board_rev); | |
385 | ||
386 | return 0; | |
387 | } | |
679549d1 | 388 | |
ea743e65 | 389 | #ifdef CONFIG_LCD |
3f41ffe4 | 390 | void exynos_lcd_misc_init(vidinfo_t *vid) |
679549d1 | 391 | { |
3f41ffe4 PW |
392 | #ifdef CONFIG_TIZEN |
393 | get_tizen_logo_info(vid); | |
679549d1 | 394 | #endif |
3f41ffe4 PW |
395 | |
396 | /* for LD9040. */ | |
397 | vid->pclk_name = 1; /* MPLL */ | |
398 | vid->sclk_div = 1; | |
399 | ||
400 | setenv("lcdinfo", "lcd=ld9040"); | |
679549d1 | 401 | } |
ea743e65 | 402 | #endif |