diff options
Diffstat (limited to 'drivers/video/starfive')
-rw-r--r-- | drivers/video/starfive/sf_hdmi.c | 539 | ||||
-rw-r--r-- | drivers/video/starfive/sf_hdmi.h | 107 | ||||
-rw-r--r-- | drivers/video/starfive/sf_mipi.c | 25 | ||||
-rw-r--r-- | drivers/video/starfive/sf_vop.c | 134 |
4 files changed, 689 insertions, 116 deletions
diff --git a/drivers/video/starfive/sf_hdmi.c b/drivers/video/starfive/sf_hdmi.c index 319080114f..80f5b11989 100644 --- a/drivers/video/starfive/sf_hdmi.c +++ b/drivers/video/starfive/sf_hdmi.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH + * Copyright (c) 2023 keith.zhao@starfivetech.com */ +#include <asm/gpio.h> +#include <asm/io.h> #include <common.h> #include <clk.h> #include <display.h> @@ -11,48 +13,549 @@ #include <edid.h> #include <regmap.h> #include <syscon.h> -#include <asm/gpio.h> -#include <asm/io.h> + #include <power/regulator.h> +#include <linux/delay.h> + #include "sf_hdmi.h" -static int rk3399_hdmi_enable(struct udevice *dev, int panel_bpp, +static int hdmi_read(struct sf_hdmi_priv *priv,uint32_t addr) +{ + return readl(priv->base + (addr) * 0x04); + +} +static void hdmi_write(struct sf_hdmi_priv *priv,int val, uint32_t addr) +{ + writel(val, priv->base + (addr) * 0x04); +} + +static void inno_hdmi_detect(struct sf_hdmi_priv *priv) +{ + int val; + val = hdmi_read(priv,0x1b0); + val |= 0x4; + hdmi_write(priv,val, 0x1b0); //set 0x1b0[2] to 1'b1 + hdmi_write(priv,0xf, 0x1cc); //set 0x1cc[3:0] to 4'b1111 + //while(!(hdmi_read(0x1cd) == 0x55)); + + /*turn on pre-PLL*/ + val = hdmi_read(priv,0x1a0); + val &= ~(0x1); + hdmi_write(priv,val, 0x1a0); + /*turn on post-PLL*/ + val = hdmi_read(priv,0x1aa); + val &= ~(0x1); + hdmi_write(priv,val, 0x1aa); + + /*wait for pre-PLL and post-PLL lock*/ + while(!(hdmi_read(priv,0x1a9) & 0x1)); + while(!(hdmi_read(priv,0x1af) & 0x1)); + + /*turn on LDO*/ + hdmi_write(priv,0x7, 0x1b4); + /*turn on serializer*/ + hdmi_write(priv,0x70, 0x1be); +} + +static void inno_hdmi_tx_phy_power_down(struct sf_hdmi_priv *priv) +{ + hdmi_write(priv,0x63, 0x00); +} + +static void inno_hdmi_config_1440x480i60(struct sf_hdmi_priv *priv) +{ +#ifdef REF_CLK_27M + const reg_value_t cfg_pll_data[] = { + /* config pll: 1440x480i, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x28}, + {0x1a4, 0x35}, + {0x1a5, 0x61}, + {0x1a6, 0x64}, + {0x1ab, 0x01}, + {0x1ac, 0x28}, + {0x1ad, 0x03}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + }; +#else + const reg_value_t cfg_pll_data[] = { + /* config pll: 1440x480i, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x64}, + {0x1a4, 0x2f}, + {0x1a5, 0x6c}, + {0x1a6, 0x64}, + {0x1ab, 0x01}, + {0x1ac, 0x50}, + {0x1ad, 0x07}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + }; +#endif + for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) { + hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg); + } + return; +} + +static void inno_hdmi_config_640x480p60(struct sf_hdmi_priv *priv) +{ +#ifdef REF_CLK_27M + const reg_value_t cfg_pll_data[] = { + /* config pll: 640x480p, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xc0}, + {0x1a3, 0x25}, + {0x1a4, 0x35}, + {0x1a5, 0x61}, + {0x1a6, 0x64}, + {0x1ab, 0x01}, + {0x1ac, 0x28}, + {0x1ad, 0x03}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + {0x1d1, 0x55}, + {0x1d2, 0x55}, + {0x1d3, 0x55}, + }; +#else + const reg_value_t cfg_pll_data[] = { + /* config pll: 640x480p, 60hz*/ + {0x1a0, 0x01}, + //{0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x64}, + {0x1a4, 0x2f}, + //{0x1a4, 0x2a}, + {0x1a5, 0x6c}, + {0x1a6, 0x64}, + {0x1ab, 0x01}, + {0x1ac, 0x50}, + //{0x1ad, 0x07}, + {0x1ad, 0x0d}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + }; +#endif + for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) { + hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg); + } + return; +} + +static void inno_hdmi_config_720x480p60(struct sf_hdmi_priv *priv) +{ +#ifdef REF_CLK_27M + const reg_value_t cfg_pll_data[] = { + /* config pll: 720x480p, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x28}, + {0x1a4, 0x35}, + {0x1a5, 0x61}, + {0x1a6, 0x64}, + {0x1ab, 0x01}, + {0x1ac, 0x28}, + {0x1ad, 0x03}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + }; +#else + const reg_value_t cfg_pll_data[] = { + /* config pll: 640x480p, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x64}, + {0x1a4, 0x2f}, + {0x1a5, 0x6c}, + {0x1a6, 0x64}, + {0x1ab, 0x01}, + {0x1ac, 0x50}, + {0x1ad, 0x07}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + }; +#endif + for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) { + hdmi_write(priv,cfg_pll_data[i].value, cfg_pll_data[i].reg); + } + return; +} + + +static void inno_hdmi_config_1280x720p60(struct sf_hdmi_priv *priv) +{ +#ifdef REF_CLK_27M + const reg_value_t cfg_pll_data[] = { + /* config pll: 720p, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x37}, + {0x1a4, 0x30}, + {0x1a5, 0x61}, + {0x1a6, 0x42}, + {0x1ab, 0x01}, + {0x1ac, 0x14}, + {0x1ad, 0x01}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + }; +#else + const reg_value_t cfg_pll_data[] = { + /* config pll: 720p, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x63}, + //{0x1a4, 0x1f}, + {0x1a4, 0x1a}, + //{0x1a5, 0x48}, + {0x1a5, 0x41}, + {0x1a6, 0x64}, + {0x1ab, 0x01}, + {0x1ac, 0x14}, + {0x1ad, 0x01}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + }; +#endif + for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) { + hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg); + } + return; +} + +static void inno_hdmi_config_1920x1080p60(struct sf_hdmi_priv *priv) +{ +#ifdef REF_CLK_27M + const reg_value_t cfg_pll_data[] = { + /* config pll: 1080p, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x6e}, + {0x1a4, 0x30}, + {0x1a5, 0x60}, + {0x1a6, 0x42}, + {0x1ab, 0x04}, + {0x1ac, 0x50}, + {0x1ad, 0x01}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + }; +#else + const reg_value_t cfg_pll_data[] = { + /* config pll: 1080p, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x63}, + {0x1a4, 0x15}, + {0x1a5, 0x41}, + {0x1a6, 0x42}, + {0x1ab, 0x01}, + //{0x1ac, 0x0a}, + {0x1ac, 0x14}, + //{0x1ad, 0x00}, + {0x1ad, 0x01}, + {0x1aa, 0x0e}, + {0x1a0, 0x00}, + }; +#endif + for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) { + hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg); + } + return; +} + +static void inno_hdmi_config_3840x2160p60(struct sf_hdmi_priv *priv) +{ +#ifdef REF_CLK_27M + const reg_value_t cfg_pll_data[] = { + /* config pll: 4K, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x63}, + {0x1a4, 0x08}, + {0x1a5, 0x01}, + {0x1a6, 0x21}, + {0x1ab, 0x04}, + {0x1ac, 0x14}, + {0x1ad, 0x00}, + {0x1aa, 0x02}, + {0x1a0, 0x00}, + }; +#else + const reg_value_t cfg_pll_data[] = { + /* config pll: 4K, 60hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x63}, + {0x1a4, 0x08}, + {0x1a5, 0x01}, + {0x1a6, 0x21}, + {0x1ab, 0x04}, + {0x1ac, 0x14}, + {0x1ad, 0x00}, + {0x1aa, 0x02}, + {0x1a0, 0x00}, + }; +#endif + for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) { + hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg); + } + return; +} + +static void inno_hdmi_config_3840x2160p30(struct sf_hdmi_priv *priv) +{ +#ifdef REF_CLK_27M + const reg_value_t cfg_pll_data[] = { + /* config pll: 4K, 30hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x03}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x58}, + {0x1a4, 0x10}, + {0x1a5, 0x41}, + {0x1a6, 0x21}, + {0x1ab, 0x04}, + {0x1ac, 0x14}, + {0x1ad, 0x00}, + {0x1aa, 0x02}, + {0x1a0, 0x00}, + }; +#else + const reg_value_t cfg_pll_data[] = { + /* config pll: 4K, 30hz*/ + {0x1a0, 0x01}, + {0x1aa, 0x0f}, + {0x1a1, 0x01}, + {0x1a2, 0xf0}, + {0x1a3, 0x63}, + {0x1a4, 0x10}, + {0x1a5, 0x41}, + {0x1a6, 0x21}, + {0x1ab, 0x04}, + {0x1ac, 0x14}, + {0x1ad, 0x00}, + {0x1aa, 0x02}, + {0x1a0, 0x00}, + }; +#endif + for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) { + hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg); + } + return; +} + +static void inno_hdmi_tx_ctrl(struct sf_hdmi_priv *priv,vic_code_t vic) +{ + hdmi_write(priv, 0x06, 0x9f); + hdmi_write(priv, 0x82, 0xa0); + hdmi_write(priv, 0xd, 0xa2); + hdmi_write(priv, 0x0, 0xa3); + hdmi_write(priv, 0x0, 0xa4); + hdmi_write(priv, 0x8, 0xa5); + hdmi_write(priv, 0x70, 0xa6); + hdmi_write(priv, vic, 0xa7); //conifg video format Identification Code + hdmi_write(priv, 0x10, 0xc9); //bist mode: 0x00, normal mode: 0x10, phy mode: 0x4 +} + +static void inno_hdmi_tx_phy_param_config(struct sf_hdmi_priv *priv,resolution_t type) +{ + vic_code_t vic; + switch(type) { + case RES_1440_480I_60HZ: + vic = VIC_1440x480i60; + inno_hdmi_config_1440x480i60(priv); + break; + case RES_640_480P_60HZ: + vic = VIC_640x480p60; + inno_hdmi_config_640x480p60(priv); + break; + case RES_720_480P_60HZ: + vic = VIC_720x480p60; + inno_hdmi_config_720x480p60(priv); + break; + case RES_1280_720P_60HZ: + vic = VIC_1280x720p60; + inno_hdmi_config_1280x720p60(priv); + break; + case RES_1920_1080P_60HZ: + vic = VIC_1920x1080p60; + inno_hdmi_config_1920x1080p60(priv); + break; + case RES_3840_2160P_30HZ: + vic = VIC_3840x2160p30; + inno_hdmi_config_3840x2160p30(priv); + break; + case RES_3840_2160P_60HZ: + vic = VIC_3840x2160p60; + inno_hdmi_config_3840x2160p60(priv); + break; + } + inno_hdmi_tx_ctrl(priv, vic); + + return; +} + +static void inno_hdmi_tx_phy_power_on(struct sf_hdmi_priv *priv) +{ + hdmi_write(priv, 0x61, 0x00); //0x61: power 0n, 0x63: power off +} + +static void inno_hdmi_data_sync(struct sf_hdmi_priv *priv) +{ + hdmi_write(priv, 0x00, 0xce); + hdmi_write(priv, 0x01, 0xce); +} + +void inno_hdmi_tmds_driver_on(struct sf_hdmi_priv *priv) +{ + hdmi_write(priv, 0x8f, 0x1b2); + mdelay(50); +} + +static int inno_hdmi_enable(struct udevice *dev, int panel_bpp, const struct display_timing *edid) { + struct sf_hdmi_priv *priv = dev_get_priv(dev); + debug("inno_hdmi_enable on\r\n"); + inno_hdmi_detect(priv); + inno_hdmi_tx_phy_power_down(priv); + inno_hdmi_tx_phy_param_config(priv,RES_1920_1080P_60HZ); + inno_hdmi_tx_phy_power_on(priv); + inno_hdmi_tmds_driver_on(priv); + /*data sync*/ + inno_hdmi_data_sync(priv); return 0; } int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) { + //need fix next return 0; } -static int rk3399_hdmi_of_to_plat(struct udevice *dev) +static int inno_hdmi_of_to_plat(struct udevice *dev) { + struct sf_hdmi_priv *priv = dev_get_priv(dev); + int ret; + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + debug("%s----priv->base = %px\n",__func__,priv->base); + + ret = clk_get_by_name(dev, "sysclk", &priv->sys_clk); + if (ret) { + pr_err("clk_get_by_name(sysclk) failed: %d", ret); + return ret; + } + + ret = clk_get_by_name(dev, "mclk", &priv->mclk); + if (ret) { + pr_err("clk_get_by_name(mclk) failed: %d\n", ret); + return ret; + } + + ret = clk_get_by_name(dev, "bclk", &priv->bclk); + if (ret) { + pr_err("clk_get_by_name(bclk) failed: %d\n", ret); + return ret; + } + + ret = reset_get_by_name(dev, "hdmi_tx", &priv->tx_rst); + if (ret) { + pr_err("failed to get hdmi_tx reset (ret=%d)\n", ret); + return ret; + } return 0; } -static int rk3399_hdmi_probe(struct udevice *dev) +static int inno_hdmi_probe(struct udevice *dev) { - return 0; + struct sf_hdmi_priv *priv = dev_get_priv(dev); + int ret; + ret = clk_enable(&priv->sys_clk); + if (ret < 0) { + pr_err("clk_enable(sys_clk) failed: %d\n", ret); + return ret; + } + + ret = clk_enable(&priv->mclk); + if (ret < 0) { + pr_err("clk_enable(mclk) failed: %d\n", ret); + goto free_clock_sys_clk; + } + + ret = clk_enable(&priv->bclk); + if (ret < 0) { + pr_err("clk_enable(bclk) failed: %d\n", ret); + goto free_clock_mclk_clk; + } + + ret = reset_deassert(&priv->tx_rst); + if (ret < 0) { + pr_err("failed to deassert tx_rst\n"); + goto free_reset; + } + + ret = (hdmi_read(priv, HDMI_STATUS) & m_HOTPLUG) ? 0 : 1; // 0 connected.. 1 disconnected + debug("ret = %d\n",ret); + return ret; + +free_reset: + clk_disable(&priv->bclk); +free_clock_mclk_clk: + clk_disable(&priv->mclk); +free_clock_sys_clk: + clk_disable(&priv->sys_clk); + + return ret; + } -static const struct dm_display_ops rk3399_hdmi_ops = { +static const struct dm_display_ops inno_hdmi_ops = { .read_edid = rk_hdmi_read_edid, - .enable = rk3399_hdmi_enable, + .enable = inno_hdmi_enable, }; -static const struct udevice_id rk3399_hdmi_ids[] = { - { .compatible = "rockchip,rk3288-dw-hdmi" }, +static const struct udevice_id inno_hdmi_ids[] = { + { .compatible = "starfive,inno-hdmi" }, { } }; -U_BOOT_DRIVER(rk3399_hdmi_rockchip) = { - .name = "rk3399_hdmi_rockchip", +U_BOOT_DRIVER(inno_hdmi_starfive) = { + .name = "inno_hdmi_starfive", .id = UCLASS_DISPLAY, - .of_match = rk3399_hdmi_ids, - .ops = &rk3399_hdmi_ops, - .of_to_plat = rk3399_hdmi_of_to_plat, - .probe = rk3399_hdmi_probe, - .priv_auto = sizeof(struct rk_hdmi_priv), + .of_match = inno_hdmi_ids, + .ops = &inno_hdmi_ops, + .of_to_plat = inno_hdmi_of_to_plat, + .probe = inno_hdmi_probe, + .priv_auto = sizeof(struct sf_hdmi_priv), }; diff --git a/drivers/video/starfive/sf_hdmi.h b/drivers/video/starfive/sf_hdmi.h index 859a0b9ff3..96177e1b0d 100644 --- a/drivers/video/starfive/sf_hdmi.h +++ b/drivers/video/starfive/sf_hdmi.h @@ -3,73 +3,60 @@ * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH */ -#ifndef __RK_HDMI_H__ -#define __RK_HDMI_H__ +#ifndef __SF_HDMI_H__ +#define __SF_HDMI_H__ -struct rkhdmi_driverdata { - /* configuration */ - u8 i2c_clk_high; - u8 i2c_clk_low; - const char * const *regulator_names; - u32 regulator_names_cnt; - /* setters/getters */ - int (*set_input_vop)(struct udevice *dev); - int (*clk_config)(struct udevice *dev); -}; +#include <clk.h> +#include <reset.h> + +#define HDMI_STATUS 0xc8 +#define m_HOTPLUG (1 << 7) +#define m_MASK_INT_HOTPLUG (1 << 5) +#define m_INT_HOTPLUG (1 << 1) +#define v_MASK_INT_HOTPLUG(n) ((n & 0x1) << 5) + +typedef struct +{ + /* TODO: add hdmi inno registers define */ +} hdmi_regs_t; -struct rk_hdmi_priv { +typedef struct register_value { + u16 reg; + u8 value; +}reg_value_t; + +struct sf_hdmi_priv { struct dw_hdmi hdmi; void *grf; + void __iomem *base; + + struct clk pclk; + struct clk sys_clk; + struct clk mclk; + struct clk bclk; + struct clk phy_clk; + struct reset_ctl tx_rst; }; -/** - * rk_hdmi_read_edid() - read the attached HDMI/DVI monitor's EDID - * - * N.B.: The buffer should be large enough to hold 2 EDID blocks, as - * this function calls dw_hdmi_read_edid, which ignores buf_size - * argument and assumes that there's always enough space for 2 - * EDID blocks. - * - * @dev: device - * @buf: output buffer for the EDID - * @buf_size: number of bytes in the buffer - * @return number of bytes read if OK, -ve if something went wrong - */ -int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size); +typedef enum { + RES_1440_480I_60HZ = 0, + RES_640_480P_60HZ, + RES_720_480P_60HZ, + RES_1280_720P_60HZ, + RES_1920_1080P_60HZ, + RES_3840_2160P_30HZ, + RES_3840_2160P_60HZ, +}resolution_t; -/** - * rk_hdmi_probe_regulators() - probe (autoset + enable) regulators - * - * Probes a list of regulators by performing autoset and enable - * operations on them. The list of regulators is an array of string - * pointers and any individual regulator-probe may fail without - * counting as an error. - * - * @dev: device - * @names: array of string-pointers to regulator names to probe - * @cnt: number of elements in the 'names' array - */ -void rk_hdmi_probe_regulators(struct udevice *dev, - const char * const *names, int cnt); -/** - * rk_hdmi_of_to_plat() - common of_to_plat implementation - * - * @dev: device - * @return 0 if OK, -ve if something went wrong - */ -int rk_hdmi_of_to_plat(struct udevice *dev); +typedef enum { + VIC_1440x480i60 = 6, + VIC_640x480p60 = 1, + VIC_720x480p60 = 2, + VIC_1280x720p60 = 4, + VIC_1920x1080p60 = 16, + VIC_3840x2160p30 = 95, + VIC_3840x2160p60 = 97, +}vic_code_t; -/** - * rk_hdmi_probe() - common probe implementation - * - * Performs the following, common initialisation steps: - * 1. checks for HPD (i.e. a HDMI monitor being attached) - * 2. initialises the Designware HDMI core - * 3. initialises the Designware HDMI PHY - * - * @dev: device - * @return 0 if OK, -ve if something went wrong - */ -int rk_hdmi_probe(struct udevice *dev); #endif diff --git a/drivers/video/starfive/sf_mipi.c b/drivers/video/starfive/sf_mipi.c index 8c2bcea845..4521f7c869 100644 --- a/drivers/video/starfive/sf_mipi.c +++ b/drivers/video/starfive/sf_mipi.c @@ -1,3 +1,5 @@ +#include <asm/gpio.h> +#include <asm/io.h> #include <common.h> #include <clk.h> #include <display.h> @@ -6,23 +8,21 @@ #include <panel.h> #include <regmap.h> #include <syscon.h> -#include <asm/gpio.h> -#include <asm/io.h> + #include <dm/uclass-internal.h> #include <linux/err.h> #include <linux/kernel.h> -#include <video_bridge.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/err.h> +#include <power/regulator.h> +#include <video_bridge.h> #include <dsi_host.h> #include <mipi_dsi.h> #include <reset.h> #include <video.h> -#include <linux/iopoll.h> -#include <linux/err.h> -#include <power/regulator.h> -#include <regmap.h> -#include <syscon.h> #include "sf_mipi.h" static inline u32 sf_dphy_get_reg(void __iomem * io_addr, u32 shift, u32 mask) @@ -72,11 +72,6 @@ static void reset(int assert, void __iomem *phy_reg) } } -static inline void sys_delay(int cycles) -{ - while (cycles--); -} - int sys_mipi_dsi_set_ppi_txbyte_hs(int enable, void *priv_data) { struct mipi_dsi_device *device = priv_data; @@ -97,7 +92,7 @@ int sys_mipi_dsi_set_ppi_txbyte_hs(int enable, void *priv_data) return ret; } } - sys_delay(100); + mdelay(100); return 0; } @@ -253,7 +248,7 @@ static int dsi_sf_attach(struct udevice *dev) ret = uclass_first_device(UCLASS_PANEL, &priv->panel); if (ret) { - printf("panel device error %d\n", ret); + debug("panel device error %d\n", ret); return ret; } debug("%s,priv->panel->name = %s\n", __func__,priv->panel->name); diff --git a/drivers/video/starfive/sf_vop.c b/drivers/video/starfive/sf_vop.c index b2ad6e4c59..8b62851dc2 100644 --- a/drivers/video/starfive/sf_vop.c +++ b/drivers/video/starfive/sf_vop.c @@ -349,6 +349,9 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node) u32 remote_phandle; ofnode remote; const char *compat; + struct display_plat *disp_uc_plat; + debug("%s(%s, 0x%lx, %s)\n", __func__, + dev_read_name(dev), fbbase, ofnode_get_name(ep_node)); struct udevice *panel = NULL; @@ -361,6 +364,7 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node) return -EINVAL; remote_vop_id = ofnode_read_u32_default(remote, "reg", -1); uc_priv->bpix = VIDEO_BPP32; + debug("remote_vop_id %d\n", remote_vop_id); /* * The remote-endpoint references into a subnode of the encoder @@ -388,14 +392,19 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node) __func__, dev_read_name(dev)); return -EINVAL; } - + debug("%s(%s, 0x%lx,remote %s)\n", __func__, + dev_read_name(dev), fbbase, ofnode_get_name(remote)); + uclass_find_device_by_ofnode(UCLASS_DISPLAY, remote, &disp); + if (disp) + break; uclass_find_device_by_ofnode(UCLASS_VIDEO_BRIDGE, remote, &disp); if (disp) break; + }; compat = ofnode_get_property(remote, "compatible", NULL); if (!compat) { - printf("%s(%s): Failed to find compatible property\n", + debug("%s(%s): Failed to find compatible property\n", __func__, dev_read_name(dev)); return -EINVAL; } @@ -410,24 +419,111 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node) } else if (strstr(compat, "lvds")) { vop_id = VOP_MODE_LVDS; } else { - printf("%s(%s): Failed to find vop mode for %s\n", + debug("%s(%s): Failed to find vop mode for %s\n", __func__, dev_read_name(dev), compat); return -EINVAL; } - ret = device_probe(disp); - if (ret) { - printf("%s: device '%s' display won't probe (ret=%d)\n", - __func__, dev->name, ret); - return ret; + debug("vop_id %d,compat = %s\n", vop_id,compat); + if(vop_id == VOP_MODE_HDMI) + { + disp_uc_plat = dev_get_uclass_plat(disp); + debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat); + + + disp_uc_plat->source_id = remote_vop_id; + disp_uc_plat->src_dev = dev; + + ret = device_probe(disp); + if (ret) { + debug("%s: device '%s' display won't probe (ret=%d)\n", + __func__, dev->name, ret); + return ret; + } + + ret = display_enable(disp, 1 << VIDEO_BPP32, &timing); + if (ret) { + debug("%s: Failed to read timings\n", __func__); + return ret; + } + int err = clk_set_parent(&priv->dc_pix0, &priv->dc_pix_src); + if (err) { + debug("failed to set %s clock as %s's parent\n", + priv->dc_pix_src.dev->name, priv->dc_pix0.dev->name); + return err; + } + + ulong new_rate = clk_set_rate(&priv->dc_pix_src, 148500000); + debug("new_rate %ld\n", new_rate); + + dc_hw_init(dev); + + uc_priv->xsize = 1920; + uc_priv->ysize = 1080; + + writel(0xc0001fff, priv->regs_hi+0x00000014); + writel(0x00002000, priv->regs_hi+0x00001cc0); + //writel(uc_plat->base+0x1fa400, priv->regs_hi+0x00001530); + writel(0x00000000, priv->regs_hi+0x00001800); + writel(0x00000000, priv->regs_hi+0x000024d8); + writel(0x021c0780, priv->regs_hi+0x000024e0); + writel(0x021c0780, priv->regs_hi+0x00001810); + writel(uc_plat->base, priv->regs_hi+0x00001400); + writel(0x00001e00, priv->regs_hi+0x00001408); + writel(0x00000f61, priv->regs_hi+0x00001ce8); + writel(0x00002042, priv->regs_hi+0x00002510); + writel(0x808a3156, priv->regs_hi+0x00002508); + writel(0x8008e1b2, priv->regs_hi+0x00002500); + writel(0x18000000, priv->regs_hi+0x00001518); + writel(0x00003000, priv->regs_hi+0x00001cc0); + writel(0x00060000, priv->regs_hi+0x00001540); + writel(0x00000001, priv->regs_hi+0x00002540); + writel(0x80060000, priv->regs_hi+0x00001540); + writel(0x00060000, priv->regs_hi+0x00001544); + writel(0x00000002, priv->regs_hi+0x00002544); + writel(0x80060000, priv->regs_hi+0x00001544); + writel(0x00060000, priv->regs_hi+0x00001548); + writel(0x0000000c, priv->regs_hi+0x00002548); + writel(0x80060000, priv->regs_hi+0x00001548); + writel(0x00060000, priv->regs_hi+0x0000154c); + writel(0x0000000d, priv->regs_hi+0x0000254c); + writel(0x80060000, priv->regs_hi+0x0000154c); + writel(0x00000001, priv->regs_hi+0x00002518); + writel(0x00000000, priv->regs_hi+0x00001a28); + writel(0x08980780, priv->regs_hi+0x00001430); + writel(0x440207d8, priv->regs_hi+0x00001438); + writel(0x04650438, priv->regs_hi+0x00001440); + writel(0x4220843c, priv->regs_hi+0x00001448); + writel(0x00000000, priv->regs_hi+0x000014b0); + writel(0x000000d2, priv->regs_hi+0x00001cd0); + writel(0x00000005, priv->regs_hi+0x000014b8); + writel(0x00000052, priv->regs_hi+0x000014d0); + writel(0xdeadbeef, priv->regs_hi+0x00001528); + writel(0x00001111, priv->regs_hi+0x00001418); + writel(0x00000000, priv->regs_hi+0x00001410); + writel(0x00000000, priv->regs_hi+0x00002518); + writel(0x00200024, priv->regs_hi+0x00001468); + writel(0x00000000, priv->regs_hi+0x00001484); + writel(0x00200024, priv->regs_hi+0x00001468); + writel(0x00000c24, priv->regs_hi+0x000024e8); + writel(0x00000000, priv->regs_hi+0x000024fc); + writel(0x00000c24, priv->regs_hi+0x000024e8); + writel(0x00000001, priv->regs_hi+0x00001ccc); + return 0; } - debug("%s,vop_id = %d\n", __func__,vop_id); if(vop_id == VOP_MODE_MIPI) { + ret = device_probe(disp); + if (ret) { + debug("%s: device '%s' display won't probe (ret=%d)\n", + __func__, dev->name, ret); + return ret; + } + ret = video_bridge_attach(disp); if (ret) { - printf("fail to attach bridge\n"); + debug("fail to attach bridge\n"); return ret; } @@ -440,7 +536,7 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node) ret = uclass_first_device_err(UCLASS_PANEL, &panel); if (ret) { if (ret != -ENODEV) - printf("panel device error %d\n", ret); + debug("panel device error %d\n", ret); return ret; } @@ -449,14 +545,14 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node) ret = ofnode_decode_display_timing(dev_ofnode(panel), 0, &timing); if (ret) { - printf("decode display timing error %d\n", ret); + debug("decode display timing error %d\n", ret); return ret; } } int err = clk_set_parent(&priv->dc_pix0, &priv->dc_pix_src); if (err) { - printf("failed to set %s clock as %s's parent\n", + debug("failed to set %s clock as %s's parent\n", priv->dc_pix_src.dev->name, priv->dc_pix0.dev->name); return err; } @@ -521,6 +617,7 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node) writel(0x00000000, priv->regs_hi+0x000024fc); //csr_reg writel(0x00011b25, priv->regs_hi+0x000024e8); //csr_reg writel(0x00000001, priv->regs_hi+0x00001ccc); //csr_reg + return 0; } return 0; @@ -547,21 +644,12 @@ static int sf_vop_probe(struct udevice *dev) vout_probe_resources_jh7110(dev); - /* - * Try all the ports until we find one that works. In practice this - * tries EDP first if available, then HDMI. - * - * Note that rockchip_vop_set_clk() always uses NPLL as the source - * clock so it is currently not possible to use more than one display - * device simultaneously. - */ port = dev_read_subnode(dev, "port"); if (!ofnode_valid(port)) { debug("%s(%s): 'port' subnode not found\n", __func__, dev_read_name(dev)); return -EINVAL; } - for (node = ofnode_first_subnode(port); ofnode_valid(node); node = dev_read_next_subnode(node)) { @@ -601,7 +689,7 @@ int sf_vop_bind(struct udevice *dev) plat->size = 4 * (CONFIG_VIDEO_STARFIVE_MAX_XRES * CONFIG_VIDEO_STARFIVE_MAX_YRES); - printf("%s,%d,plat->size = %d\n",__func__,__LINE__,plat->size); + debug("%s,%d,plat->size = %d\n",__func__,__LINE__,plat->size); return 0; } |