blob: 7532f7c0b2007b3f2d095be9dcf0dd19506c591d [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Xiubo Lidd048322014-12-16 14:50:33 +08002/*
3 * Copyright 2014 Freescale Semiconductor, Inc.
Biwen Li9ebde882019-12-31 15:33:44 +08004 * Copyright 2019 NXP
Xiubo Lidd048322014-12-16 14:50:33 +08005 *
6 * FSL DCU Framebuffer driver
Xiubo Lidd048322014-12-16 14:50:33 +08007 */
8
Simon Glass401d1c42020-10-30 21:38:53 -06009#include <asm/global_data.h>
Xiubo Lidd048322014-12-16 14:50:33 +080010#include <asm/io.h>
11#include <common.h>
12#include <fsl_dcu_fb.h>
13#include <i2c.h>
14#include "div64.h"
15#include "../common/diu_ch7301.h"
16#include "ls1021aqds_qixis.h"
17
18DECLARE_GLOBAL_DATA_PTR;
19
Biwen Li9ebde882019-12-31 15:33:44 +080020static int select_i2c_ch_pca9547(u8 ch, int bus_num)
Xiubo Lidd048322014-12-16 14:50:33 +080021{
22 int ret;
Igor Opaniuk2147a162021-02-09 13:52:45 +020023#if CONFIG_IS_ENABLED(DM_I2C)
Biwen Li9ebde882019-12-31 15:33:44 +080024 struct udevice *dev;
Xiubo Lidd048322014-12-16 14:50:33 +080025
Biwen Li9ebde882019-12-31 15:33:44 +080026 ret = i2c_get_chip_for_busnum(bus_num, I2C_MUX_PCA_ADDR_PRI,
27 1, &dev);
28 if (ret) {
29 printf("%s: Cannot find udev for a bus %d\n", __func__,
30 bus_num);
31 return ret;
32 }
33 ret = dm_i2c_write(dev, 0, &ch, 1);
34#else
Xiubo Lidd048322014-12-16 14:50:33 +080035 ret = i2c_write(I2C_MUX_PCA_ADDR_PRI, 0, 1, &ch, 1);
Biwen Li9ebde882019-12-31 15:33:44 +080036#endif
Xiubo Lidd048322014-12-16 14:50:33 +080037 if (ret) {
38 puts("PCA: failed to select proper channel\n");
39 return ret;
40 }
41
42 return 0;
43}
44
45unsigned int dcu_set_pixel_clock(unsigned int pixclock)
46{
47 unsigned long long div;
48
49 div = (unsigned long long)(gd->bus_clk / 1000);
50 div *= (unsigned long long)pixclock;
51 do_div(div, 1000000000);
52
53 return div;
54}
55
Igor Opaniuka6eedb62019-06-10 14:47:49 +030056int platform_dcu_init(struct fb_info *fbinfo,
57 unsigned int xres,
58 unsigned int yres,
Xiubo Lidd048322014-12-16 14:50:33 +080059 const char *port,
60 struct fb_videomode *dcu_fb_videomode)
61{
62 const char *name;
63 unsigned int pixel_format;
64 int ret;
65 u8 ch;
66
67 /* Mux I2C3+I2C4 as HSYNC+VSYNC */
Igor Opaniuk2147a162021-02-09 13:52:45 +020068#if CONFIG_IS_ENABLED(DM_I2C)
Biwen Li9ebde882019-12-31 15:33:44 +080069 struct udevice *dev;
70
71 /* QIXIS device mount on I2C1 bus*/
72 ret = i2c_get_chip_for_busnum(0, CONFIG_SYS_I2C_QIXIS_ADDR,
73 1, &dev);
74 if (ret) {
75 printf("%s: Cannot find udev for a bus %d\n", __func__,
76 0);
77 return ret;
78 }
79 ret = dm_i2c_read(dev, QIXIS_DCU_BRDCFG5, &ch, 1);
80 if (ret) {
81 printf("Error: failed to read I2C @%02x\n",
82 CONFIG_SYS_I2C_QIXIS_ADDR);
83 return ret;
84 }
85 ch &= 0x1F;
86 ch |= 0xA0;
87 ret = dm_i2c_write(dev, QIXIS_DCU_BRDCFG5, &ch, 1);
88
89#else
Xiubo Lidd048322014-12-16 14:50:33 +080090 ret = i2c_read(CONFIG_SYS_I2C_QIXIS_ADDR, QIXIS_DCU_BRDCFG5,
91 1, &ch, 1);
92 if (ret) {
93 printf("Error: failed to read I2C @%02x\n",
94 CONFIG_SYS_I2C_QIXIS_ADDR);
95 return ret;
96 }
97 ch &= 0x1F;
98 ch |= 0xA0;
99 ret = i2c_write(CONFIG_SYS_I2C_QIXIS_ADDR, QIXIS_DCU_BRDCFG5,
100 1, &ch, 1);
Biwen Li9ebde882019-12-31 15:33:44 +0800101#endif
Xiubo Lidd048322014-12-16 14:50:33 +0800102 if (ret) {
103 printf("Error: failed to write I2C @%02x\n",
104 CONFIG_SYS_I2C_QIXIS_ADDR);
105 return ret;
106 }
107
108 if (strncmp(port, "hdmi", 4) == 0) {
109 unsigned long pixval;
110
111 name = "HDMI";
112
113 pixval = 1000000000 / dcu_fb_videomode->pixclock;
114 pixval *= 1000;
115
Igor Opaniuk2147a162021-02-09 13:52:45 +0200116#if !CONFIG_IS_ENABLED(DM_I2C)
Xiubo Lidd048322014-12-16 14:50:33 +0800117 i2c_set_bus_num(CONFIG_SYS_I2C_DVI_BUS_NUM);
Biwen Li9ebde882019-12-31 15:33:44 +0800118#endif
119 select_i2c_ch_pca9547(I2C_MUX_CH_CH7301,
120 CONFIG_SYS_I2C_DVI_BUS_NUM);
Xiubo Lidd048322014-12-16 14:50:33 +0800121 diu_set_dvi_encoder(pixval);
Biwen Li9ebde882019-12-31 15:33:44 +0800122 select_i2c_ch_pca9547(I2C_MUX_CH_DEFAULT,
123 CONFIG_SYS_I2C_DVI_BUS_NUM);
Xiubo Lidd048322014-12-16 14:50:33 +0800124 } else {
125 return 0;
126 }
127
128 printf("DCU: Switching to %s monitor @ %ux%u\n", name, xres, yres);
129
130 pixel_format = 32;
Igor Opaniuka6eedb62019-06-10 14:47:49 +0300131 fsl_dcu_init(fbinfo, xres, yres, pixel_format);
Xiubo Lidd048322014-12-16 14:50:33 +0800132
133 return 0;
134}