~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/u-boot/drivers/video/tegra.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011 The Chromium OS Authors.
 
3
 * SPDX-License-Identifier:     GPL-2.0+
 
4
 */
 
5
 
 
6
#include <common.h>
 
7
#include <fdtdec.h>
 
8
#include <lcd.h>
 
9
 
 
10
#include <asm/system.h>
 
11
#include <asm/gpio.h>
 
12
 
 
13
#include <asm/arch/clock.h>
 
14
#include <asm/arch/funcmux.h>
 
15
#include <asm/arch/pinmux.h>
 
16
#include <asm/arch/pwm.h>
 
17
#include <asm/arch/display.h>
 
18
#include <asm/arch-tegra/timer.h>
 
19
 
 
20
DECLARE_GLOBAL_DATA_PTR;
 
21
 
 
22
/* These are the stages we go throuh in enabling the LCD */
 
23
enum stage_t {
 
24
        STAGE_START,
 
25
        STAGE_PANEL_VDD,
 
26
        STAGE_LVDS,
 
27
        STAGE_BACKLIGHT_VDD,
 
28
        STAGE_PWM,
 
29
        STAGE_BACKLIGHT_EN,
 
30
        STAGE_DONE,
 
31
};
 
32
 
 
33
static enum stage_t stage;      /* Current stage we are at */
 
34
static unsigned long timer_next; /* Time we can move onto next stage */
 
35
 
 
36
/* Our LCD config, set up in handle_stage() */
 
37
static struct fdt_panel_config config;
 
38
struct fdt_disp_config *disp_config;    /* Display controller config */
 
39
 
 
40
enum {
 
41
        /* Maximum LCD size we support */
 
42
        LCD_MAX_WIDTH           = 1366,
 
43
        LCD_MAX_HEIGHT          = 768,
 
44
        LCD_MAX_LOG2_BPP        = 4,            /* 2^4 = 16 bpp */
 
45
};
 
46
 
 
47
vidinfo_t panel_info = {
 
48
        /* Insert a value here so that we don't end up in the BSS */
 
49
        .vl_col = -1,
 
50
};
 
51
 
 
52
#ifndef CONFIG_OF_CONTROL
 
53
#error "You must enable CONFIG_OF_CONTROL to get Tegra LCD support"
 
54
#endif
 
55
 
 
56
static void update_panel_size(struct fdt_disp_config *config)
 
57
{
 
58
        panel_info.vl_col = config->width;
 
59
        panel_info.vl_row = config->height;
 
60
        panel_info.vl_bpix = config->log2_bpp;
 
61
}
 
62
 
 
63
/*
 
64
 *  Main init function called by lcd driver.
 
65
 *  Inits and then prints test pattern if required.
 
66
 */
 
67
 
 
68
void lcd_ctrl_init(void *lcdbase)
 
69
{
 
70
        int type = DCACHE_OFF;
 
71
        int size;
 
72
 
 
73
        assert(disp_config);
 
74
 
 
75
        /* Make sure that we can acommodate the selected LCD */
 
76
        assert(disp_config->width <= LCD_MAX_WIDTH);
 
77
        assert(disp_config->height <= LCD_MAX_HEIGHT);
 
78
        assert(disp_config->log2_bpp <= LCD_MAX_LOG2_BPP);
 
79
        if (disp_config->width <= LCD_MAX_WIDTH
 
80
                        && disp_config->height <= LCD_MAX_HEIGHT
 
81
                        && disp_config->log2_bpp <= LCD_MAX_LOG2_BPP)
 
82
                update_panel_size(disp_config);
 
83
        size = lcd_get_size(&lcd_line_length);
 
84
 
 
85
        /* Set up the LCD caching as requested */
 
86
        if (config.cache_type & FDT_LCD_CACHE_WRITE_THROUGH)
 
87
                type = DCACHE_WRITETHROUGH;
 
88
        else if (config.cache_type & FDT_LCD_CACHE_WRITE_BACK)
 
89
                type = DCACHE_WRITEBACK;
 
90
        mmu_set_region_dcache_behaviour(disp_config->frame_buffer, size, type);
 
91
 
 
92
        /* Enable flushing after LCD writes if requested */
 
93
        lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH);
 
94
 
 
95
        debug("LCD frame buffer at %08X\n", disp_config->frame_buffer);
 
96
}
 
97
 
 
98
ulong calc_fbsize(void)
 
99
{
 
100
        return (panel_info.vl_col * panel_info.vl_row *
 
101
                NBITS(panel_info.vl_bpix)) / 8;
 
102
}
 
103
 
 
104
void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
 
105
{
 
106
}
 
107
 
 
108
void tegra_lcd_early_init(const void *blob)
 
109
{
 
110
        /*
 
111
         * Go with the maximum size for now. We will fix this up after
 
112
         * relocation. These values are only used for memory alocation.
 
113
         */
 
114
        panel_info.vl_col = LCD_MAX_WIDTH;
 
115
        panel_info.vl_row = LCD_MAX_HEIGHT;
 
116
        panel_info.vl_bpix = LCD_MAX_LOG2_BPP;
 
117
}
 
118
 
 
119
/**
 
120
 * Decode the panel information from the fdt.
 
121
 *
 
122
 * @param blob          fdt blob
 
123
 * @param config        structure to store fdt config into
 
124
 * @return 0 if ok, -ve on error
 
125
 */
 
126
static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config)
 
127
{
 
128
        int display_node;
 
129
 
 
130
        disp_config = tegra_display_get_config();
 
131
        if (!disp_config) {
 
132
                debug("%s: Display controller is not configured\n", __func__);
 
133
                return -1;
 
134
        }
 
135
        display_node = disp_config->panel_node;
 
136
        if (display_node < 0) {
 
137
                debug("%s: No panel configuration available\n", __func__);
 
138
                return -1;
 
139
        }
 
140
 
 
141
        config->pwm_channel = pwm_request(blob, display_node, "nvidia,pwm");
 
142
        if (config->pwm_channel < 0) {
 
143
                debug("%s: Unable to request PWM channel\n", __func__);
 
144
                return -1;
 
145
        }
 
146
 
 
147
        config->cache_type = fdtdec_get_int(blob, display_node,
 
148
                                            "nvidia,cache-type",
 
149
                                            FDT_LCD_CACHE_WRITE_BACK_FLUSH);
 
150
 
 
151
        /* These GPIOs are all optional */
 
152
        fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-enable-gpios",
 
153
                            &config->backlight_en);
 
154
        fdtdec_decode_gpio(blob, display_node, "nvidia,lvds-shutdown-gpios",
 
155
                           &config->lvds_shutdown);
 
156
        fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-vdd-gpios",
 
157
                           &config->backlight_vdd);
 
158
        fdtdec_decode_gpio(blob, display_node, "nvidia,panel-vdd-gpios",
 
159
                           &config->panel_vdd);
 
160
 
 
161
        return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings",
 
162
                        config->panel_timings, FDT_LCD_TIMINGS);
 
163
}
 
164
 
 
165
/**
 
166
 * Handle the next stage of device init
 
167
 */
 
168
static int handle_stage(const void *blob)
 
169
{
 
170
        debug("%s: stage %d\n", __func__, stage);
 
171
 
 
172
        /* do the things for this stage */
 
173
        switch (stage) {
 
174
        case STAGE_START:
 
175
                /* Initialize the Tegra display controller */
 
176
                if (tegra_display_probe(gd->fdt_blob, (void *)gd->fb_base)) {
 
177
                        printf("%s: Failed to probe display driver\n",
 
178
                        __func__);
 
179
                        return -1;
 
180
                }
 
181
 
 
182
                /* get panel details */
 
183
                if (fdt_decode_lcd(blob, &config)) {
 
184
                        printf("No valid LCD information in device tree\n");
 
185
                        return -1;
 
186
                }
 
187
 
 
188
                /*
 
189
                 * It is possible that the FDT has requested that the LCD be
 
190
                 * disabled. We currently don't support this. It would require
 
191
                 * changes to U-Boot LCD subsystem to have LCD support
 
192
                 * compiled in but not used. An easier option might be to
 
193
                 * still have a frame buffer, but leave the backlight off and
 
194
                 * remove all mention of lcd in the stdout environment
 
195
                 * variable.
 
196
                 */
 
197
 
 
198
                funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
 
199
 
 
200
                fdtdec_setup_gpio(&config.panel_vdd);
 
201
                fdtdec_setup_gpio(&config.lvds_shutdown);
 
202
                fdtdec_setup_gpio(&config.backlight_vdd);
 
203
                fdtdec_setup_gpio(&config.backlight_en);
 
204
 
 
205
                /*
 
206
                 * TODO: If fdt includes output flag we can omit this code
 
207
                 * since fdtdec_setup_gpio will do it for us.
 
208
                 */
 
209
                if (fdt_gpio_isvalid(&config.panel_vdd))
 
210
                        gpio_direction_output(config.panel_vdd.gpio, 0);
 
211
                if (fdt_gpio_isvalid(&config.lvds_shutdown))
 
212
                        gpio_direction_output(config.lvds_shutdown.gpio, 0);
 
213
                if (fdt_gpio_isvalid(&config.backlight_vdd))
 
214
                        gpio_direction_output(config.backlight_vdd.gpio, 0);
 
215
                if (fdt_gpio_isvalid(&config.backlight_en))
 
216
                        gpio_direction_output(config.backlight_en.gpio, 0);
 
217
                break;
 
218
        case STAGE_PANEL_VDD:
 
219
                if (fdt_gpio_isvalid(&config.panel_vdd))
 
220
                        gpio_direction_output(config.panel_vdd.gpio, 1);
 
221
                break;
 
222
        case STAGE_LVDS:
 
223
                if (fdt_gpio_isvalid(&config.lvds_shutdown))
 
224
                        gpio_set_value(config.lvds_shutdown.gpio, 1);
 
225
                break;
 
226
        case STAGE_BACKLIGHT_VDD:
 
227
                if (fdt_gpio_isvalid(&config.backlight_vdd))
 
228
                        gpio_set_value(config.backlight_vdd.gpio, 1);
 
229
                break;
 
230
        case STAGE_PWM:
 
231
                /* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
 
232
                pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_PWM);
 
233
                pinmux_tristate_disable(PMUX_PINGRP_GPU);
 
234
 
 
235
                pwm_enable(config.pwm_channel, 32768, 0xdf, 1);
 
236
                break;
 
237
        case STAGE_BACKLIGHT_EN:
 
238
                if (fdt_gpio_isvalid(&config.backlight_en))
 
239
                        gpio_set_value(config.backlight_en.gpio, 1);
 
240
                break;
 
241
        case STAGE_DONE:
 
242
                break;
 
243
        }
 
244
 
 
245
        /* set up timer for next stage */
 
246
        timer_next = timer_get_us();
 
247
        if (stage < FDT_LCD_TIMINGS)
 
248
                timer_next += config.panel_timings[stage] * 1000;
 
249
 
 
250
        /* move to next stage */
 
251
        stage++;
 
252
        return 0;
 
253
}
 
254
 
 
255
int tegra_lcd_check_next_stage(const void *blob, int wait)
 
256
{
 
257
        if (stage == STAGE_DONE)
 
258
                return 0;
 
259
 
 
260
        do {
 
261
                /* wait if we need to */
 
262
                debug("%s: stage %d\n", __func__, stage);
 
263
                if (stage != STAGE_START) {
 
264
                        int delay = timer_next - timer_get_us();
 
265
 
 
266
                        if (delay > 0) {
 
267
                                if (wait)
 
268
                                        udelay(delay);
 
269
                                else
 
270
                                        return 0;
 
271
                        }
 
272
                }
 
273
 
 
274
                if (handle_stage(blob))
 
275
                        return -1;
 
276
        } while (wait && stage != STAGE_DONE);
 
277
        if (stage == STAGE_DONE)
 
278
                debug("%s: LCD init complete\n", __func__);
 
279
 
 
280
        return 0;
 
281
}
 
282
 
 
283
void lcd_enable(void)
 
284
{
 
285
        /*
 
286
         * Backlight and power init will be done separately in
 
287
         * tegra_lcd_check_next_stage(), which should be called in
 
288
         * board_late_init().
 
289
         *
 
290
         * U-Boot code supports only colour depth, selected at compile time.
 
291
         * The device tree setting should match this. Otherwise the display
 
292
         * will not look right, and U-Boot may crash.
 
293
         */
 
294
        if (disp_config->log2_bpp != LCD_BPP) {
 
295
                printf("%s: Error: LCD depth configured in FDT (%d = %dbpp)"
 
296
                        " must match setting of LCD_BPP (%d)\n", __func__,
 
297
                       disp_config->log2_bpp, disp_config->bpp, LCD_BPP);
 
298
        }
 
299
}