diff options
Diffstat (limited to 'arch/arm/mach-tegra/board-whistler-panel.c')
-rw-r--r-- | arch/arm/mach-tegra/board-whistler-panel.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/board-whistler-panel.c b/arch/arm/mach-tegra/board-whistler-panel.c new file mode 100644 index 00000000000..74075d4659c --- /dev/null +++ b/arch/arm/mach-tegra/board-whistler-panel.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-tegra/board-whistler-panel.c | ||
3 | * | ||
4 | * Copyright (c) 2010-2012, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/delay.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <linux/resource.h> | ||
25 | #include <asm/mach-types.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/earlysuspend.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pwm_backlight.h> | ||
30 | #include <linux/tegra_pwm_bl.h> | ||
31 | #include <linux/nvhost.h> | ||
32 | #include <mach/nvmap.h> | ||
33 | #include <mach/irqs.h> | ||
34 | #include <mach/iomap.h> | ||
35 | #include <mach/dc.h> | ||
36 | #include <mach/fb.h> | ||
37 | |||
38 | #include "devices.h" | ||
39 | #include "gpio-names.h" | ||
40 | #include "board.h" | ||
41 | |||
42 | #define whistler_hdmi_hpd TEGRA_GPIO_PN7 | ||
43 | |||
44 | #ifdef CONFIG_TEGRA_DC | ||
45 | static struct regulator *whistler_hdmi_reg = NULL; | ||
46 | static struct regulator *whistler_hdmi_pll = NULL; | ||
47 | #endif | ||
48 | |||
49 | /* | ||
50 | * In case which_pwm is TEGRA_PWM_PM0, | ||
51 | * gpio_conf_to_sfio should be TEGRA_GPIO_PW0: set LCD_CS1_N pin to SFIO | ||
52 | * In case which_pwm is TEGRA_PWM_PM1, | ||
53 | * gpio_conf_to_sfio should be TEGRA_GPIO_PW1: set LCD_M1 pin to SFIO | ||
54 | */ | ||
55 | static struct platform_tegra_pwm_backlight_data whistler_disp1_backlight_data = { | ||
56 | .which_dc = 0, | ||
57 | .which_pwm = TEGRA_PWM_PM1, | ||
58 | .max_brightness = 256, | ||
59 | .dft_brightness = 77, | ||
60 | .gpio_conf_to_sfio = TEGRA_GPIO_PW1, | ||
61 | .switch_to_sfio = &tegra_gpio_disable, | ||
62 | .period = 0x1F, | ||
63 | .clk_div = 3, | ||
64 | .clk_select = 2, | ||
65 | }; | ||
66 | |||
67 | static struct platform_device whistler_disp1_backlight_device = { | ||
68 | .name = "tegra-pwm-bl", | ||
69 | .id = -1, | ||
70 | .dev = { | ||
71 | .platform_data = &whistler_disp1_backlight_data, | ||
72 | }, | ||
73 | }; | ||
74 | |||
75 | #ifdef CONFIG_TEGRA_DC | ||
76 | static int whistler_hdmi_enable(void) | ||
77 | { | ||
78 | if (!whistler_hdmi_reg) { | ||
79 | whistler_hdmi_reg = regulator_get(NULL, "avdd_hdmi"); /* LD011 */ | ||
80 | if (IS_ERR_OR_NULL(whistler_hdmi_reg)) { | ||
81 | pr_err("hdmi: couldn't get regulator avdd_hdmi\n"); | ||
82 | whistler_hdmi_reg = NULL; | ||
83 | return PTR_ERR(whistler_hdmi_reg); | ||
84 | } | ||
85 | } | ||
86 | regulator_enable(whistler_hdmi_reg); | ||
87 | |||
88 | if (!whistler_hdmi_pll) { | ||
89 | whistler_hdmi_pll = regulator_get(NULL, "avdd_hdmi_pll"); /* LD06 */ | ||
90 | if (IS_ERR_OR_NULL(whistler_hdmi_pll)) { | ||
91 | pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n"); | ||
92 | whistler_hdmi_pll = NULL; | ||
93 | regulator_disable(whistler_hdmi_reg); | ||
94 | whistler_hdmi_reg = NULL; | ||
95 | return PTR_ERR(whistler_hdmi_pll); | ||
96 | } | ||
97 | } | ||
98 | regulator_enable(whistler_hdmi_pll); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int whistler_hdmi_disable(void) | ||
103 | { | ||
104 | regulator_disable(whistler_hdmi_reg); | ||
105 | regulator_disable(whistler_hdmi_pll); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static struct resource whistler_disp1_resources[] = { | ||
110 | { | ||
111 | .name = "irq", | ||
112 | .start = INT_DISPLAY_GENERAL, | ||
113 | .end = INT_DISPLAY_GENERAL, | ||
114 | .flags = IORESOURCE_IRQ, | ||
115 | }, | ||
116 | { | ||
117 | .name = "regs", | ||
118 | .start = TEGRA_DISPLAY_BASE, | ||
119 | .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1, | ||
120 | .flags = IORESOURCE_MEM, | ||
121 | }, | ||
122 | { | ||
123 | .name = "fbmem", | ||
124 | .flags = IORESOURCE_MEM, | ||
125 | }, | ||
126 | }; | ||
127 | |||
128 | static struct resource whistler_disp2_resources[] = { | ||
129 | { | ||
130 | .name = "irq", | ||
131 | .start = INT_DISPLAY_B_GENERAL, | ||
132 | .end = INT_DISPLAY_B_GENERAL, | ||
133 | .flags = IORESOURCE_IRQ, | ||
134 | }, | ||
135 | { | ||
136 | .name = "regs", | ||
137 | .start = TEGRA_DISPLAY2_BASE, | ||
138 | .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1, | ||
139 | .flags = IORESOURCE_MEM, | ||
140 | }, | ||
141 | { | ||
142 | .name = "fbmem", | ||
143 | .flags = IORESOURCE_MEM, | ||
144 | }, | ||
145 | { | ||
146 | .name = "hdmi_regs", | ||
147 | .start = TEGRA_HDMI_BASE, | ||
148 | .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1, | ||
149 | .flags = IORESOURCE_MEM, | ||
150 | }, | ||
151 | }; | ||
152 | |||
153 | static struct tegra_dc_mode whistler_panel_modes[] = { | ||
154 | { | ||
155 | .pclk = 27000000, | ||
156 | .h_ref_to_sync = 4, | ||
157 | .v_ref_to_sync = 2, | ||
158 | .h_sync_width = 10, | ||
159 | .v_sync_width = 3, | ||
160 | .h_back_porch = 20, | ||
161 | .v_back_porch = 3, | ||
162 | .h_active = 800, | ||
163 | .v_active = 480, | ||
164 | .h_front_porch = 70, | ||
165 | .v_front_porch = 3, | ||
166 | }, | ||
167 | }; | ||
168 | |||
169 | static struct tegra_dc_out_pin whistler_dc_out_pins[] = { | ||
170 | { | ||
171 | .name = TEGRA_DC_OUT_PIN_H_SYNC, | ||
172 | .pol = TEGRA_DC_OUT_PIN_POL_LOW, | ||
173 | }, | ||
174 | { | ||
175 | .name = TEGRA_DC_OUT_PIN_V_SYNC, | ||
176 | .pol = TEGRA_DC_OUT_PIN_POL_LOW, | ||
177 | }, | ||
178 | { | ||
179 | .name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK, | ||
180 | .pol = TEGRA_DC_OUT_PIN_POL_LOW, | ||
181 | }, | ||
182 | }; | ||
183 | |||
184 | static u8 whistler_dc_out_pin_sel_config[] = { | ||
185 | TEGRA_PIN_OUT_CONFIG_SEL_LM1_PM1, | ||
186 | }; | ||
187 | |||
188 | static struct tegra_dc_out whistler_disp1_out = { | ||
189 | .type = TEGRA_DC_OUT_RGB, | ||
190 | |||
191 | .align = TEGRA_DC_ALIGN_MSB, | ||
192 | .order = TEGRA_DC_ORDER_RED_BLUE, | ||
193 | |||
194 | .height = 54, /* mm */ | ||
195 | .width = 90, /* mm */ | ||
196 | |||
197 | .modes = whistler_panel_modes, | ||
198 | .n_modes = ARRAY_SIZE(whistler_panel_modes), | ||
199 | |||
200 | .out_pins = whistler_dc_out_pins, | ||
201 | .n_out_pins = ARRAY_SIZE(whistler_dc_out_pins), | ||
202 | |||
203 | .out_sel_configs = whistler_dc_out_pin_sel_config, | ||
204 | .n_out_sel_configs = ARRAY_SIZE(whistler_dc_out_pin_sel_config), | ||
205 | }; | ||
206 | |||
207 | static struct tegra_dc_out whistler_disp2_out = { | ||
208 | .type = TEGRA_DC_OUT_HDMI, | ||
209 | .flags = TEGRA_DC_OUT_HOTPLUG_HIGH, | ||
210 | |||
211 | .dcc_bus = 1, | ||
212 | .hotplug_gpio = whistler_hdmi_hpd, | ||
213 | |||
214 | .max_pixclock = KHZ2PICOS(148500), | ||
215 | |||
216 | .align = TEGRA_DC_ALIGN_MSB, | ||
217 | .order = TEGRA_DC_ORDER_RED_BLUE, | ||
218 | |||
219 | .enable = whistler_hdmi_enable, | ||
220 | .disable = whistler_hdmi_disable, | ||
221 | }; | ||
222 | |||
223 | static struct tegra_fb_data whistler_fb_data = { | ||
224 | .win = 0, | ||
225 | .xres = 800, | ||
226 | .yres = 480, | ||
227 | .bits_per_pixel = 32, | ||
228 | .flags = TEGRA_FB_FLIP_ON_PROBE, | ||
229 | }; | ||
230 | |||
231 | static struct tegra_fb_data whistler_hdmi_fb_data = { | ||
232 | .win = 0, | ||
233 | .xres = 800, | ||
234 | .yres = 480, | ||
235 | .bits_per_pixel = 32, | ||
236 | .flags = TEGRA_FB_FLIP_ON_PROBE, | ||
237 | }; | ||
238 | |||
239 | |||
240 | static struct tegra_dc_platform_data whistler_disp1_pdata = { | ||
241 | .flags = TEGRA_DC_FLAG_ENABLED, | ||
242 | .default_out = &whistler_disp1_out, | ||
243 | .fb = &whistler_fb_data, | ||
244 | }; | ||
245 | |||
246 | static struct nvhost_device whistler_disp1_device = { | ||
247 | .name = "tegradc", | ||
248 | .id = 0, | ||
249 | .resource = whistler_disp1_resources, | ||
250 | .num_resources = ARRAY_SIZE(whistler_disp1_resources), | ||
251 | .dev = { | ||
252 | .platform_data = &whistler_disp1_pdata, | ||
253 | }, | ||
254 | }; | ||
255 | |||
256 | static struct tegra_dc_platform_data whistler_disp2_pdata = { | ||
257 | .flags = 0, | ||
258 | .default_out = &whistler_disp2_out, | ||
259 | .fb = &whistler_hdmi_fb_data, | ||
260 | }; | ||
261 | |||
262 | static struct nvhost_device whistler_disp2_device = { | ||
263 | .name = "tegradc", | ||
264 | .id = 1, | ||
265 | .resource = whistler_disp2_resources, | ||
266 | .num_resources = ARRAY_SIZE(whistler_disp2_resources), | ||
267 | .dev = { | ||
268 | .platform_data = &whistler_disp2_pdata, | ||
269 | }, | ||
270 | }; | ||
271 | #endif | ||
272 | |||
273 | #if defined(CONFIG_TEGRA_NVMAP) | ||
274 | static struct nvmap_platform_carveout whistler_carveouts[] = { | ||
275 | [0] = NVMAP_HEAP_CARVEOUT_IRAM_INIT, | ||
276 | [1] = { | ||
277 | .name = "generic-0", | ||
278 | .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC, | ||
279 | .base = 0x18C00000, | ||
280 | .size = SZ_128M - 0xC00000, | ||
281 | .buddy_size = SZ_32K, | ||
282 | }, | ||
283 | }; | ||
284 | |||
285 | static struct nvmap_platform_data whistler_nvmap_data = { | ||
286 | .carveouts = whistler_carveouts, | ||
287 | .nr_carveouts = ARRAY_SIZE(whistler_carveouts), | ||
288 | }; | ||
289 | |||
290 | static struct platform_device whistler_nvmap_device = { | ||
291 | .name = "tegra-nvmap", | ||
292 | .id = -1, | ||
293 | .dev = { | ||
294 | .platform_data = &whistler_nvmap_data, | ||
295 | }, | ||
296 | }; | ||
297 | #endif | ||
298 | |||
299 | static struct platform_device *whistler_gfx_devices[] __initdata = { | ||
300 | #if defined(CONFIG_TEGRA_NVMAP) | ||
301 | &whistler_nvmap_device, | ||
302 | #endif | ||
303 | &whistler_disp1_backlight_device, | ||
304 | }; | ||
305 | |||
306 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
307 | /* put early_suspend/late_resume handlers here for the display in order | ||
308 | * to keep the code out of the display driver, keeping it closer to upstream | ||
309 | */ | ||
310 | struct early_suspend whistler_panel_early_suspender; | ||
311 | |||
312 | static void whistler_panel_early_suspend(struct early_suspend *h) | ||
313 | { | ||
314 | /* power down LCD, add use a blank screen for HDMI */ | ||
315 | if (num_registered_fb > 0) | ||
316 | fb_blank(registered_fb[0], FB_BLANK_POWERDOWN); | ||
317 | if (num_registered_fb > 1) | ||
318 | fb_blank(registered_fb[1], FB_BLANK_NORMAL); | ||
319 | |||
320 | #ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND | ||
321 | cpufreq_save_default_governor(); | ||
322 | cpufreq_set_conservative_governor(); | ||
323 | cpufreq_set_conservative_governor_param("up_threshold", | ||
324 | SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD); | ||
325 | |||
326 | cpufreq_set_conservative_governor_param("down_threshold", | ||
327 | SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD); | ||
328 | |||
329 | cpufreq_set_conservative_governor_param("freq_step", | ||
330 | SET_CONSERVATIVE_GOVERNOR_FREQ_STEP); | ||
331 | #endif | ||
332 | } | ||
333 | |||
334 | static void whistler_panel_late_resume(struct early_suspend *h) | ||
335 | { | ||
336 | unsigned i; | ||
337 | #ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND | ||
338 | cpufreq_restore_default_governor(); | ||
339 | #endif | ||
340 | for (i = 0; i < num_registered_fb; i++) | ||
341 | fb_blank(registered_fb[i], FB_BLANK_UNBLANK); | ||
342 | } | ||
343 | #endif | ||
344 | |||
345 | int __init whistler_panel_init(void) | ||
346 | { | ||
347 | int err; | ||
348 | struct resource __maybe_unused *res; | ||
349 | |||
350 | tegra_gpio_enable(whistler_hdmi_hpd); | ||
351 | gpio_request(whistler_hdmi_hpd, "hdmi_hpd"); | ||
352 | gpio_direction_input(whistler_hdmi_hpd); | ||
353 | |||
354 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
355 | whistler_panel_early_suspender.suspend = whistler_panel_early_suspend; | ||
356 | whistler_panel_early_suspender.resume = whistler_panel_late_resume; | ||
357 | whistler_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; | ||
358 | register_early_suspend(&whistler_panel_early_suspender); | ||
359 | #endif | ||
360 | |||
361 | #if defined(CONFIG_TEGRA_NVMAP) | ||
362 | whistler_carveouts[1].base = tegra_carveout_start; | ||
363 | whistler_carveouts[1].size = tegra_carveout_size; | ||
364 | #endif | ||
365 | |||
366 | #ifdef CONFIG_TEGRA_GRHOST | ||
367 | err = nvhost_device_register(&tegra_grhost_device); | ||
368 | if (err) | ||
369 | return err; | ||
370 | #endif | ||
371 | |||
372 | err = platform_add_devices(whistler_gfx_devices, | ||
373 | ARRAY_SIZE(whistler_gfx_devices)); | ||
374 | |||
375 | #if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC) | ||
376 | res = nvhost_get_resource_byname(&whistler_disp1_device, | ||
377 | IORESOURCE_MEM, "fbmem"); | ||
378 | res->start = tegra_fb_start; | ||
379 | res->end = tegra_fb_start + tegra_fb_size - 1; | ||
380 | #endif | ||
381 | |||
382 | /* Copy the bootloader fb to the fb. */ | ||
383 | tegra_move_framebuffer(tegra_fb_start, tegra_bootloader_fb_start, | ||
384 | min(tegra_fb_size, tegra_bootloader_fb_size)); | ||
385 | |||
386 | #if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC) | ||
387 | res = nvhost_get_resource_byname(&whistler_disp2_device, | ||
388 | IORESOURCE_MEM, "fbmem"); | ||
389 | res->start = tegra_fb2_start; | ||
390 | res->end = tegra_fb2_start + tegra_fb2_size - 1; | ||
391 | |||
392 | if (!err) | ||
393 | err = nvhost_device_register(&whistler_disp1_device); | ||
394 | |||
395 | if (!err) | ||
396 | err = nvhost_device_register(&whistler_disp2_device); | ||
397 | #endif | ||
398 | |||
399 | return err; | ||
400 | } | ||
401 | |||