powerpc/t1040qds: Add Video - HDMI support
[karo-tx-uboot.git] / board / freescale / t1040qds / diu.c
1 /*
2  * Copyright 2014 Freescale Semiconductor, Inc.
3  * Author: Priyanka Jain <Priyanka.Jain@freescale.com>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <command.h>
10 #include <linux/ctype.h>
11 #include <asm/io.h>
12 #include <stdio_dev.h>
13 #include <video_fb.h>
14 #include <fsl_diu_fb.h>
15 #include "../common/qixis.h"
16 #include "t1040qds.h"
17 #include "t1040qds_qixis.h"
18 #include <i2c.h>
19
20
21 #define I2C_DVI_INPUT_DATA_FORMAT_REG           0x1F
22 #define I2C_DVI_PLL_CHARGE_CNTL_REG             0x33
23 #define I2C_DVI_PLL_DIVIDER_REG                 0x34
24 #define I2C_DVI_PLL_SUPPLY_CNTL_REG             0x35
25 #define I2C_DVI_PLL_FILTER_REG                  0x36
26 #define I2C_DVI_TEST_PATTERN_REG                0x48
27 #define I2C_DVI_POWER_MGMT_REG                  0x49
28 #define I2C_DVI_LOCK_STATE_REG                  0x4D
29 #define I2C_DVI_SYNC_POLARITY_REG               0x56
30
31 /*
32  * Set VSYNC/HSYNC to active high. This is polarity of sync signals
33  * from DIU->DVI. The DIU default is active igh, so DVI is set to
34  * active high.
35  */
36 #define I2C_DVI_INPUT_DATA_FORMAT_VAL           0x98
37
38 #define I2C_DVI_PLL_CHARGE_CNTL_HIGH_SPEED_VAL  0x06
39 #define I2C_DVI_PLL_DIVIDER_HIGH_SPEED_VAL      0x26
40 #define I2C_DVI_PLL_FILTER_HIGH_SPEED_VAL       0xA0
41 #define I2C_DVI_PLL_CHARGE_CNTL_LOW_SPEED_VAL   0x08
42 #define I2C_DVI_PLL_DIVIDER_LOW_SPEED_VAL       0x16
43 #define I2C_DVI_PLL_FILTER_LOW_SPEED_VAL        0x60
44
45 /* Clear test pattern */
46 #define I2C_DVI_TEST_PATTERN_VAL                0x18
47 /* Exit Power-down mode */
48 #define I2C_DVI_POWER_MGMT_VAL                  0xC0
49
50 /* Monitor polarity is handled via DVI Sync Polarity Register */
51 #define I2C_DVI_SYNC_POLARITY_VAL               0x00
52
53 /*
54  * DIU Area Descriptor
55  *
56  * Note that we need to byte-swap the value before it's written to the AD
57  * register.  So even though the registers don't look like they're in the same
58  * bit positions as they are on the MPC8610, the same value is written to the
59  * AD register on the MPC8610 and on the P1022.
60  */
61 #define AD_BYTE_F               0x10000000
62 #define AD_ALPHA_C_SHIFT        25
63 #define AD_BLUE_C_SHIFT         23
64 #define AD_GREEN_C_SHIFT        21
65 #define AD_RED_C_SHIFT          19
66 #define AD_PIXEL_S_SHIFT        16
67 #define AD_COMP_3_SHIFT         12
68 #define AD_COMP_2_SHIFT         8
69 #define AD_COMP_1_SHIFT         4
70 #define AD_COMP_0_SHIFT         0
71
72 /* Programming of HDMI Chrontel CH7301 connector */
73 int diu_set_dvi_encoder(unsigned int pixclock)
74 {
75         int ret;
76         u8 temp;
77         select_i2c_ch_pca9547(I2C_MUX_CH_DIU);
78
79         temp = I2C_DVI_TEST_PATTERN_VAL;
80         ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_TEST_PATTERN_REG, 1,
81                         &temp, 1);
82         if (ret) {
83                 puts("I2C: failed to select proper dvi test pattern\n");
84                 return ret;
85         }
86         temp = I2C_DVI_INPUT_DATA_FORMAT_VAL;
87         ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_INPUT_DATA_FORMAT_REG,
88                         1, &temp, 1);
89         if (ret) {
90                 puts("I2C: failed to select dvi input data format\n");
91                 return ret;
92         }
93
94         /* Set Sync polarity register */
95         temp = I2C_DVI_SYNC_POLARITY_VAL;
96         ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_SYNC_POLARITY_REG, 1,
97                         &temp, 1);
98         if (ret) {
99                 puts("I2C: failed to select dvi syc polarity\n");
100                 return ret;
101         }
102
103         /* Set PLL registers based on pixel clock rate*/
104         if (pixclock > 65000000) {
105                 temp = I2C_DVI_PLL_CHARGE_CNTL_HIGH_SPEED_VAL;
106                 ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
107                                 I2C_DVI_PLL_CHARGE_CNTL_REG, 1, &temp, 1);
108                 if (ret) {
109                         puts("I2C: failed to select dvi pll charge_cntl\n");
110                         return ret;
111                 }
112                 temp = I2C_DVI_PLL_DIVIDER_HIGH_SPEED_VAL;
113                 ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
114                                 I2C_DVI_PLL_DIVIDER_REG, 1, &temp, 1);
115                 if (ret) {
116                         puts("I2C: failed to select dvi pll divider\n");
117                         return ret;
118                 }
119                 temp = I2C_DVI_PLL_FILTER_HIGH_SPEED_VAL;
120                 ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
121                                 I2C_DVI_PLL_FILTER_REG, 1, &temp, 1);
122                 if (ret) {
123                         puts("I2C: failed to select dvi pll filter\n");
124                         return ret;
125                 }
126         } else {
127                 temp = I2C_DVI_PLL_CHARGE_CNTL_LOW_SPEED_VAL;
128                 ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
129                                 I2C_DVI_PLL_CHARGE_CNTL_REG, 1, &temp, 1);
130                 if (ret) {
131                         puts("I2C: failed to select dvi pll charge_cntl\n");
132                         return ret;
133                 }
134                 temp = I2C_DVI_PLL_DIVIDER_LOW_SPEED_VAL;
135                 ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
136                                 I2C_DVI_PLL_DIVIDER_REG, 1, &temp, 1);
137                 if (ret) {
138                         puts("I2C: failed to select dvi pll divider\n");
139                         return ret;
140                 }
141                 temp = I2C_DVI_PLL_FILTER_LOW_SPEED_VAL;
142                 ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
143                                 I2C_DVI_PLL_FILTER_REG, 1, &temp, 1);
144                 if (ret) {
145                         puts("I2C: failed to select dvi pll filter\n");
146                         return ret;
147                 }
148         }
149
150         temp = I2C_DVI_POWER_MGMT_VAL;
151         ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_POWER_MGMT_REG, 1,
152                         &temp, 1);
153         if (ret) {
154                 puts("I2C: failed to select dvi power mgmt\n");
155                 return ret;
156         }
157
158         udelay(500);
159
160         select_i2c_ch_pca9547(I2C_MUX_CH_DEFAULT);
161         return 0;
162 }
163
164 void diu_set_pixel_clock(unsigned int pixclock)
165 {
166         unsigned long speed_ccb, temp;
167         u32 pixval;
168         int ret = 0;
169         speed_ccb = get_bus_freq(0);
170         temp = 1000000000 / pixclock;
171         temp *= 1000;
172         pixval = speed_ccb / temp;
173
174         /* Program HDMI encoder */
175         ret = diu_set_dvi_encoder(temp);
176         if (ret) {
177                 puts("Failed to set DVI encoder\n");
178                 return;
179         }
180
181         /* Program pixel clock */
182         out_be32((unsigned *)CONFIG_SYS_FSL_SCFG_PIXCLK_ADDR,
183                  ((pixval << PXCK_BITS_START) & PXCK_MASK));
184         /* enable clock*/
185         out_be32((unsigned *)CONFIG_SYS_FSL_SCFG_PIXCLK_ADDR, PXCKEN_MASK |
186                  ((pixval << PXCK_BITS_START) & PXCK_MASK));
187 }
188
189 int platform_diu_init(unsigned int xres, unsigned int yres, const char *port)
190 {
191         u32 pixel_format;
192         u8 sw;
193
194         /*Route I2C4 to DIU system as HSYNC/VSYNC*/
195         sw = QIXIS_READ(brdcfg[5]);
196         QIXIS_WRITE(brdcfg[5],
197                     ((sw & ~(BRDCFG5_IMX_MASK)) | (BRDCFG5_IMX_DIU)));
198
199         /*Configure Display ouput port as HDMI*/
200         sw = QIXIS_READ(brdcfg[15]);
201         QIXIS_WRITE(brdcfg[15],
202                     ((sw & ~(BRDCFG15_LCDPD_MASK | BRDCFG15_DIUSEL_MASK))
203                       | (BRDCFG15_LCDPD_ENABLED | BRDCFG15_DIUSEL_HDMI)));
204
205         pixel_format = cpu_to_le32(AD_BYTE_F | (3 << AD_ALPHA_C_SHIFT) |
206                 (0 << AD_BLUE_C_SHIFT) | (1 << AD_GREEN_C_SHIFT) |
207                 (2 << AD_RED_C_SHIFT) | (8 << AD_COMP_3_SHIFT) |
208                 (8 << AD_COMP_2_SHIFT) | (8 << AD_COMP_1_SHIFT) |
209                 (8 << AD_COMP_0_SHIFT) | (3 << AD_PIXEL_S_SHIFT));
210
211         printf("DIU:   Switching to monitor @ %ux%u\n",  xres, yres);
212
213
214         return fsl_diu_init(xres, yres, pixel_format, 0);
215 }