mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
Merge commit 'e6cc02852f60a1ad3a9d8061e0fbdf23125ff148'
* commit 'e6cc02852f60a1ad3a9d8061e0fbdf23125ff148': Revert "mfd: Add rk628 mfd driver" Revert "drm/rockchip: Add rk628 display driver" Revert "drm/rockchip: rk628: Add hdmi driver" Revert "drm/rockchip/rk628: Add GVI driver" Revert "drm: rockchip: rk628: Add rk628 combrx-phy driver" Revert "drm: rockchip: rk628: Add rk628 hdmirx driver" Revert "pinctrl: rk628: add rk628 pinctrl driver" Revert "nvmem: rk628-efuse: add rk628 efuse driver" Change-Id: I11874bb11345600b610ac9e5422fd238297993aa
This commit is contained in:
@@ -165,6 +165,5 @@ config ROCKCHIP_DW_HDCP2
|
||||
Designware HDCP2 Controller.
|
||||
|
||||
source "drivers/gpu/drm/rockchip/rk618/Kconfig"
|
||||
source "drivers/gpu/drm/rockchip/rk628/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
@@ -31,4 +31,3 @@ rockchipdrm-$(CONFIG_DRM_ROCKCHIP_VVOP) += rockchip_drm_vvop.o
|
||||
obj-$(CONFIG_ROCKCHIP_DW_HDCP2) += dw_hdcp2.o
|
||||
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
|
||||
obj-$(CONFIG_DRM_ROCKCHIP_RK618) += rk618/
|
||||
obj-$(CONFIG_DRM_ROCKCHIP_RK628) += rk628/
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config DRM_ROCKCHIP_RK628
|
||||
tristate "Rockchip RK628 display bridge driver"
|
||||
depends on DRM_ROCKCHIP
|
||||
depends on MFD_RK628
|
||||
help
|
||||
Rockchip RK628 display bridge chips driver.
|
||||
@@ -1,14 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the Rockchip RK628 display bridge driver.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_DRM_ROCKCHIP_RK628) += rk628_combrxphy.o \
|
||||
rk628_combtxphy.o \
|
||||
rk628_dsi.o \
|
||||
rk628_gvi.o \
|
||||
rk628_lvds.o \
|
||||
rk628_post_process.o \
|
||||
rk628_rgb.o \
|
||||
rk628_hdmi.o \
|
||||
rk628_hdmirx.o
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,520 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <asm/bitsperlong.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/mfd/rk628.h>
|
||||
|
||||
#include "rk628_combtxphy.h"
|
||||
|
||||
#define REG(x) ((x) + 0x90000)
|
||||
|
||||
#define COMBTXPHY_CON0 REG(0x0000)
|
||||
#define SW_TX_IDLE_MASK GENMASK(29, 20)
|
||||
#define SW_TX_IDLE(x) UPDATE(x, 29, 20)
|
||||
#define SW_TX_PD_MASK GENMASK(17, 8)
|
||||
#define SW_TX_PD(x) UPDATE(x, 17, 8)
|
||||
#define SW_BUS_WIDTH_MASK GENMASK(6, 5)
|
||||
#define SW_BUS_WIDTH_7BIT UPDATE(0x3, 6, 5)
|
||||
#define SW_BUS_WIDTH_8BIT UPDATE(0x2, 6, 5)
|
||||
#define SW_BUS_WIDTH_9BIT UPDATE(0x1, 6, 5)
|
||||
#define SW_BUS_WIDTH_10BIT UPDATE(0x0, 6, 5)
|
||||
#define SW_PD_PLL_MASK BIT(4)
|
||||
#define SW_PD_PLL BIT(4)
|
||||
#define SW_GVI_LVDS_EN_MASK BIT(3)
|
||||
#define SW_GVI_LVDS_EN BIT(3)
|
||||
#define SW_MIPI_DSI_EN_MASK BIT(2)
|
||||
#define SW_MIPI_DSI_EN BIT(2)
|
||||
#define SW_MODULEB_EN_MASK BIT(1)
|
||||
#define SW_MODULEB_EN BIT(1)
|
||||
#define SW_MODULEA_EN_MASK BIT(0)
|
||||
#define SW_MODULEA_EN BIT(0)
|
||||
#define COMBTXPHY_CON1 REG(0x0004)
|
||||
#define COMBTXPHY_CON2 REG(0x0008)
|
||||
#define COMBTXPHY_CON3 REG(0x000c)
|
||||
#define COMBTXPHY_CON4 REG(0x0010)
|
||||
#define COMBTXPHY_CON5 REG(0x0014)
|
||||
#define SW_RATE(x) UPDATE(x, 26, 24)
|
||||
#define SW_REF_DIV(x) UPDATE(x, 20, 16)
|
||||
#define SW_PLL_FB_DIV(x) UPDATE(x, 14, 10)
|
||||
#define SW_PLL_FRAC_DIV(x) UPDATE(x, 9, 0)
|
||||
#define COMBTXPHY_CON6 REG(0x0018)
|
||||
#define COMBTXPHY_CON7 REG(0x001c)
|
||||
#define SW_TX_RTERM_MASK GENMASK(22, 20)
|
||||
#define SW_TX_RTERM(x) UPDATE(x, 22, 20)
|
||||
#define SW_TX_MODE_MASK GENMASK(17, 16)
|
||||
#define SW_TX_MODE(x) UPDATE(x, 17, 16)
|
||||
#define SW_TX_CTL_CON5_MASK BIT(10)
|
||||
#define SW_TX_CTL_CON5(x) UPDATE(x, 10, 10)
|
||||
#define SW_TX_CTL_CON4_MASK GENMASK(9, 8)
|
||||
#define SW_TX_CTL_CON4(x) UPDATE(x, 9, 8)
|
||||
#define BYPASS_095V_LDO_MASK BIT(3)
|
||||
#define BYPASS_095V_LDO(x) UPDATE(x, 3, 3)
|
||||
#define TX_COM_VOLT_ADJ_MASK GENMASK(2, 0)
|
||||
#define TX_COM_VOLT_ADJ(x) UPDATE(x, 2, 0)
|
||||
#define COMBTXPHY_CON8 REG(0x0020)
|
||||
#define COMBTXPHY_CON9 REG(0x0024)
|
||||
#define SW_DSI_FSET_EN_MASK BIT(29)
|
||||
#define SW_DSI_FSET_EN BIT(29)
|
||||
#define SW_DSI_RCAL_EN_MASK BIT(28)
|
||||
#define SW_DSI_RCAL_EN BIT(28)
|
||||
#define COMBTXPHY_CON10 REG(0x0028)
|
||||
#define TX9_CKDRV_EN BIT(9)
|
||||
#define TX8_CKDRV_EN BIT(8)
|
||||
#define TX7_CKDRV_EN BIT(7)
|
||||
#define TX6_CKDRV_EN BIT(6)
|
||||
#define TX5_CKDRV_EN BIT(5)
|
||||
#define TX4_CKDRV_EN BIT(4)
|
||||
#define TX3_CKDRV_EN BIT(3)
|
||||
#define TX2_CKDRV_EN BIT(2)
|
||||
#define TX1_CKDRV_EN BIT(1)
|
||||
#define TX0_CKDRV_EN BIT(0)
|
||||
#define COMBTXPHY_MAX_REGISTER COMBTXPHY_CON10
|
||||
|
||||
struct rk628_combtxphy {
|
||||
struct device *dev;
|
||||
struct rk628 *parent;
|
||||
struct regmap *grf;
|
||||
struct regmap *regmap;
|
||||
struct clk *pclk;
|
||||
struct clk *ref_clk;
|
||||
struct reset_control *rstc;
|
||||
unsigned int flags;
|
||||
|
||||
u16 frac_div;
|
||||
u8 ref_div;
|
||||
u8 fb_div;
|
||||
u8 rate_div;
|
||||
u8 division_mode;
|
||||
};
|
||||
|
||||
static int rk628_combtxphy_dsi_power_on(struct rk628_combtxphy *combtxphy)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
|
||||
SW_MIPI_DSI_EN_MASK,
|
||||
SW_BUS_WIDTH_8BIT | SW_MIPI_DSI_EN);
|
||||
|
||||
if (combtxphy->flags & COMBTXPHY_MODULEA_EN)
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_MODULEA_EN_MASK, SW_MODULEA_EN);
|
||||
if (combtxphy->flags & COMBTXPHY_MODULEB_EN)
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_MODULEB_EN_MASK, SW_MODULEB_EN);
|
||||
|
||||
regmap_write(combtxphy->regmap, COMBTXPHY_CON5,
|
||||
SW_REF_DIV(combtxphy->ref_div - 1) |
|
||||
SW_PLL_FB_DIV(combtxphy->fb_div) |
|
||||
SW_PLL_FRAC_DIV(combtxphy->frac_div) |
|
||||
SW_RATE(combtxphy->rate_div / 2));
|
||||
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_PD_PLL, 0);
|
||||
|
||||
ret = regmap_read_poll_timeout(combtxphy->grf, GRF_DPHY0_STATUS,
|
||||
val, val & DPHY_PHYLOCK, 0, 1000);
|
||||
if (ret < 0) {
|
||||
dev_err(combtxphy->dev, "phy is not lock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON9,
|
||||
SW_DSI_FSET_EN_MASK | SW_DSI_RCAL_EN_MASK,
|
||||
SW_DSI_FSET_EN | SW_DSI_RCAL_EN);
|
||||
|
||||
usleep_range(200, 400);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk628_combtxphy_lvds_power_on(struct rk628_combtxphy *combtxphy)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
/* Adjust terminal resistance 133 ohm, bypass 0.95v ldo for driver. */
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON7,
|
||||
SW_TX_RTERM_MASK | SW_TX_MODE_MASK |
|
||||
BYPASS_095V_LDO_MASK | TX_COM_VOLT_ADJ_MASK,
|
||||
SW_TX_RTERM(6) | SW_TX_MODE(3) |
|
||||
BYPASS_095V_LDO(1) | TX_COM_VOLT_ADJ(0));
|
||||
|
||||
regmap_write(combtxphy->regmap, COMBTXPHY_CON10,
|
||||
TX7_CKDRV_EN | TX2_CKDRV_EN);
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
|
||||
SW_MIPI_DSI_EN_MASK,
|
||||
SW_BUS_WIDTH_7BIT | SW_GVI_LVDS_EN);
|
||||
|
||||
if (combtxphy->flags & COMBTXPHY_MODULEA_EN)
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_MODULEA_EN_MASK, SW_MODULEA_EN);
|
||||
if (combtxphy->flags & COMBTXPHY_MODULEB_EN)
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_MODULEB_EN_MASK, SW_MODULEB_EN);
|
||||
|
||||
regmap_write(combtxphy->regmap, COMBTXPHY_CON5,
|
||||
SW_REF_DIV(combtxphy->ref_div - 1) |
|
||||
SW_PLL_FB_DIV(combtxphy->fb_div) |
|
||||
SW_PLL_FRAC_DIV(combtxphy->frac_div) |
|
||||
SW_RATE(combtxphy->rate_div / 2));
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_PD_PLL, 0);
|
||||
|
||||
ret = regmap_read_poll_timeout(combtxphy->grf, GRF_DPHY0_STATUS,
|
||||
val, val & DPHY_PHYLOCK, 0, 1000);
|
||||
if (ret < 0) {
|
||||
dev_info(combtxphy->dev, "phy is not lock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(100, 200);
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_TX_IDLE_MASK | SW_TX_PD_MASK, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk628_combtxphy_gvi_power_on(struct rk628_combtxphy *combtxphy)
|
||||
{
|
||||
int ref_div = 0;
|
||||
|
||||
if (combtxphy->ref_div % 2) {
|
||||
ref_div = combtxphy->ref_div - 1;
|
||||
} else {
|
||||
ref_div = BIT(4);
|
||||
ref_div |= combtxphy->ref_div / 2 - 1;
|
||||
}
|
||||
regmap_write(combtxphy->regmap, COMBTXPHY_CON5,
|
||||
SW_REF_DIV(ref_div) |
|
||||
SW_PLL_FB_DIV(combtxphy->fb_div) |
|
||||
SW_PLL_FRAC_DIV(combtxphy->frac_div) |
|
||||
SW_RATE(combtxphy->rate_div / 2));
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
|
||||
SW_MIPI_DSI_EN_MASK |
|
||||
SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK,
|
||||
SW_BUS_WIDTH_10BIT | SW_GVI_LVDS_EN |
|
||||
SW_MODULEB_EN | SW_MODULEA_EN);
|
||||
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_PD_PLL | SW_TX_PD_MASK, 0);
|
||||
usleep_range(100, 200);
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_TX_IDLE_MASK, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rk628_combtxphy_set_gvi_division_mode(struct phy *phy, u8 mode)
|
||||
{
|
||||
struct rk628_combtxphy *combtxphy = phy_get_drvdata(phy);
|
||||
|
||||
combtxphy->division_mode = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rk628_combtxphy_set_gvi_division_mode);
|
||||
|
||||
static int rk628_combtxphy_power_on(struct phy *phy)
|
||||
{
|
||||
struct rk628_combtxphy *combtxphy = phy_get_drvdata(phy);
|
||||
enum phy_mode mode = phy_get_mode(phy);
|
||||
|
||||
clk_prepare_enable(combtxphy->pclk);
|
||||
reset_control_assert(combtxphy->rstc);
|
||||
udelay(10);
|
||||
reset_control_deassert(combtxphy->rstc);
|
||||
udelay(10);
|
||||
|
||||
regcache_mark_dirty(combtxphy->regmap);
|
||||
regcache_sync(combtxphy->regmap);
|
||||
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_TX_IDLE_MASK | SW_TX_PD_MASK | SW_PD_PLL_MASK,
|
||||
SW_TX_IDLE(0x3ff) | SW_TX_PD(0x3ff) | SW_PD_PLL);
|
||||
|
||||
switch (mode) {
|
||||
case PHY_MODE_MIPI_DPHY:
|
||||
regmap_update_bits(combtxphy->grf, GRF_POST_PROC_CON,
|
||||
SW_TXPHY_REFCLK_SEL_MASK,
|
||||
SW_TXPHY_REFCLK_SEL(0));
|
||||
return rk628_combtxphy_dsi_power_on(combtxphy);
|
||||
case PHY_MODE_LVDS:
|
||||
regmap_update_bits(combtxphy->grf, GRF_POST_PROC_CON,
|
||||
SW_TXPHY_REFCLK_SEL_MASK,
|
||||
SW_TXPHY_REFCLK_SEL(1));
|
||||
return rk628_combtxphy_lvds_power_on(combtxphy);
|
||||
default:
|
||||
regmap_update_bits(combtxphy->grf, GRF_POST_PROC_CON,
|
||||
SW_TXPHY_REFCLK_SEL_MASK,
|
||||
SW_TXPHY_REFCLK_SEL(2));
|
||||
return rk628_combtxphy_gvi_power_on(combtxphy);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk628_combtxphy_power_off(struct phy *phy)
|
||||
{
|
||||
struct rk628_combtxphy *combtxphy = phy_get_drvdata(phy);
|
||||
|
||||
regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
|
||||
SW_TX_IDLE_MASK | SW_TX_PD_MASK | SW_PD_PLL_MASK |
|
||||
SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK,
|
||||
SW_TX_IDLE(0x3ff) | SW_TX_PD(0x3ff) | SW_PD_PLL);
|
||||
|
||||
clk_disable_unprepare(combtxphy->pclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk628_combtxphy_set_mode(struct phy *phy, enum phy_mode mode,
|
||||
int submode)
|
||||
{
|
||||
struct rk628_combtxphy *combtxphy = phy_get_drvdata(phy);
|
||||
unsigned int bus_width = phy_get_bus_width(phy);
|
||||
unsigned int frac_rate, fin = 24;
|
||||
unsigned long fvco, fpfd;
|
||||
|
||||
switch (mode) {
|
||||
case PHY_MODE_MIPI_DPHY:
|
||||
{
|
||||
unsigned int fhsc = bus_width >> 8;
|
||||
unsigned int flags = bus_width & 0xff;
|
||||
|
||||
fhsc = fin * (fhsc / fin);
|
||||
|
||||
if (fhsc < 80 || fhsc > 1500)
|
||||
return -EINVAL;
|
||||
else if (fhsc < 375)
|
||||
combtxphy->rate_div = 4;
|
||||
else if (fhsc < 750)
|
||||
combtxphy->rate_div = 2;
|
||||
else
|
||||
combtxphy->rate_div = 1;
|
||||
|
||||
combtxphy->flags = flags;
|
||||
|
||||
fvco = fhsc * 2 * combtxphy->rate_div;
|
||||
combtxphy->ref_div = 1;
|
||||
combtxphy->fb_div = fvco / 8 / fin;
|
||||
frac_rate = fvco - (fin * 8 * combtxphy->fb_div);
|
||||
|
||||
if (frac_rate) {
|
||||
frac_rate <<= 10;
|
||||
frac_rate /= fin * 8;
|
||||
combtxphy->frac_div = frac_rate;
|
||||
} else {
|
||||
combtxphy->frac_div = 0;
|
||||
}
|
||||
|
||||
fvco = fin * (1024 * combtxphy->fb_div + combtxphy->frac_div);
|
||||
fvco *= 8;
|
||||
fvco = DIV_ROUND_UP(fvco, 1024 * combtxphy->ref_div);
|
||||
fhsc = fvco / 2 / combtxphy->rate_div;
|
||||
phy_set_bus_width(phy, fhsc);
|
||||
break;
|
||||
}
|
||||
case PHY_MODE_LVDS:
|
||||
{
|
||||
unsigned int flags = bus_width & 0xff;
|
||||
unsigned int rate = (bus_width >> 8) * 7;
|
||||
|
||||
combtxphy->flags = flags;
|
||||
combtxphy->ref_div = 1;
|
||||
combtxphy->fb_div = 14;
|
||||
combtxphy->frac_div = 0;
|
||||
|
||||
if (rate < 500)
|
||||
combtxphy->rate_div = 4;
|
||||
else if (rate < 1000)
|
||||
combtxphy->rate_div = 2;
|
||||
else
|
||||
combtxphy->rate_div = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
unsigned int i, delta_freq, best_delta_freq, fb_div;
|
||||
unsigned long ref_clk;
|
||||
unsigned long long pre_clk;
|
||||
|
||||
if (bus_width < 500000 || bus_width > 4000000)
|
||||
return -EINVAL;
|
||||
else if (bus_width < 1000000)
|
||||
combtxphy->rate_div = 4;
|
||||
else if (bus_width < 2000000)
|
||||
combtxphy->rate_div = 2;
|
||||
else
|
||||
combtxphy->rate_div = 1;
|
||||
fvco = bus_width * combtxphy->rate_div;
|
||||
ref_clk = clk_get_rate(combtxphy->ref_clk) / 1000; /* khz */
|
||||
if (combtxphy->division_mode)
|
||||
ref_clk /= 2;
|
||||
|
||||
if (!ref_clk)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* the reference clock at PFD(FPFD = ref_clk / ref_div) about
|
||||
* 25MHz is recommende, FPFD must range from 16MHz to 35MHz,
|
||||
* here to find the best rev_div.
|
||||
*/
|
||||
best_delta_freq = ref_clk;
|
||||
for (i = 1; i <= 32; i++) {
|
||||
fpfd = ref_clk / i;
|
||||
delta_freq = abs(fpfd - 25000);
|
||||
if (delta_freq < best_delta_freq) {
|
||||
best_delta_freq = delta_freq;
|
||||
combtxphy->ref_div = i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ref_clk / ref_div * 8 * fb_div = FVCO
|
||||
*/
|
||||
pre_clk = (unsigned long long)fvco / 8 * combtxphy->ref_div * 1024;
|
||||
do_div(pre_clk, ref_clk);
|
||||
fb_div = pre_clk / 1024;
|
||||
|
||||
/*
|
||||
* get the actually frequence
|
||||
*/
|
||||
bus_width = ref_clk / combtxphy->ref_div * 8;
|
||||
bus_width *= fb_div;
|
||||
bus_width /= combtxphy->rate_div;
|
||||
|
||||
combtxphy->frac_div = 0;
|
||||
combtxphy->fb_div = fb_div;
|
||||
|
||||
phy_set_bus_width(phy, bus_width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops rk628_combtxphy_ops = {
|
||||
.set_mode = rk628_combtxphy_set_mode,
|
||||
.power_on = rk628_combtxphy_power_on,
|
||||
.power_off = rk628_combtxphy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct regmap_range rk628_combtxphy_readable_ranges[] = {
|
||||
regmap_reg_range(COMBTXPHY_CON0, COMBTXPHY_CON10),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table rk628_combtxphy_readable_table = {
|
||||
.yes_ranges = rk628_combtxphy_readable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(rk628_combtxphy_readable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config rk628_combtxphy_regmap_cfg = {
|
||||
.name = "combtxphy",
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.max_register = COMBTXPHY_MAX_REGISTER,
|
||||
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.rd_table = &rk628_combtxphy_readable_table,
|
||||
};
|
||||
|
||||
static int rk628_combtxphy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rk628_combtxphy *combtxphy;
|
||||
struct phy_provider *phy_provider;
|
||||
struct phy *phy;
|
||||
int ret;
|
||||
|
||||
combtxphy = devm_kzalloc(dev, sizeof(*combtxphy), GFP_KERNEL);
|
||||
if (!combtxphy)
|
||||
return -ENOMEM;
|
||||
|
||||
combtxphy->dev = dev;
|
||||
combtxphy->parent = rk628;
|
||||
combtxphy->grf = rk628->grf;
|
||||
platform_set_drvdata(pdev, combtxphy);
|
||||
|
||||
combtxphy->pclk = devm_clk_get(dev, "pclk");
|
||||
if (IS_ERR(combtxphy->pclk))
|
||||
return PTR_ERR(combtxphy->pclk);
|
||||
|
||||
combtxphy->ref_clk = devm_clk_get(dev, "ref_clk");
|
||||
if (IS_ERR(combtxphy->ref_clk)) {
|
||||
dev_err(dev, "fail to get ref clk\n");
|
||||
return PTR_ERR(combtxphy->ref_clk);
|
||||
}
|
||||
|
||||
combtxphy->rstc = of_reset_control_get(dev->of_node, NULL);
|
||||
if (IS_ERR(combtxphy->rstc)) {
|
||||
ret = PTR_ERR(combtxphy->rstc);
|
||||
dev_err(dev, "failed to get reset control: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
combtxphy->regmap = devm_regmap_init_i2c(rk628->client,
|
||||
&rk628_combtxphy_regmap_cfg);
|
||||
if (IS_ERR(combtxphy->regmap)) {
|
||||
ret = PTR_ERR(combtxphy->regmap);
|
||||
dev_err(dev, "failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
phy = devm_phy_create(dev, NULL, &rk628_combtxphy_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
ret = PTR_ERR(phy);
|
||||
dev_err(dev, "failed to create phy: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
phy_set_drvdata(phy, combtxphy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider)) {
|
||||
ret = PTR_ERR(phy_provider);
|
||||
dev_err(dev, "failed to register phy provider: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rk628_combtxphy_of_match[] = {
|
||||
{ .compatible = "rockchip,rk628-combtxphy", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk628_combtxphy_of_match);
|
||||
|
||||
static struct platform_driver rk628_combtxphy_driver = {
|
||||
.driver = {
|
||||
.name = "rk628-combtxphy",
|
||||
.of_match_table = of_match_ptr(rk628_combtxphy_of_match),
|
||||
},
|
||||
.probe = rk628_combtxphy_probe,
|
||||
};
|
||||
module_platform_driver(rk628_combtxphy_driver);
|
||||
|
||||
MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Rockchip RK628 GVI/LVDS/MIPI Combo TX PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1,13 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*/
|
||||
|
||||
#ifndef RK628_COMBTXPHY_H_
|
||||
#define RK628_COMBTXPHY_H_
|
||||
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
int rk628_combtxphy_set_gvi_division_mode(struct phy *phy, u8 mode);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,666 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Sandy Huang <hjc@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/media-bus-format.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/mfd/rk628.h>
|
||||
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <video/of_display_timing.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
#include "rk628_combtxphy.h"
|
||||
|
||||
#define HOSTREG(x) ((x) + 0x80000)
|
||||
#define GVI_SYS_CTRL0 HOSTREG(0x0000)
|
||||
#define GVI_SYS_CTRL1 HOSTREG(0x0004)
|
||||
#define GVI_SYS_CTRL2 HOSTREG(0x0008)
|
||||
#define GVI_SYS_CTRL3 HOSTREG(0x000c)
|
||||
#define GVI_VERSION HOSTREG(0x0010)
|
||||
#define GVI_SYS_RST HOSTREG(0x0014)
|
||||
#define GVI_LINE_FLAG HOSTREG(0x0018)
|
||||
#define GVI_STATUS HOSTREG(0x001c)
|
||||
#define GVI_PLL_LOCK_TIMEOUT HOSTREG(0x0030)
|
||||
#define GVI_HTPDN_TIMEOUT HOSTREG(0x0034)
|
||||
#define GVI_LOCKN_TIMEOUT HOSTREG(0x0038)
|
||||
#define GVI_WAIT_LOCKN HOSTREG(0x003C)
|
||||
#define GVI_WAIT_HTPDN HOSTREG(0x0040)
|
||||
#define GVI_INTR_EN HOSTREG(0x0050)
|
||||
#define GVI_INTR_CLR HOSTREG(0x0054)
|
||||
#define GVI_INTR_RAW_STATUS HOSTREG(0x0058)
|
||||
#define GVI_INTR_STATUS HOSTREG(0x005c)
|
||||
#define GVI_COLOR_BAR_CTRL HOSTREG(0x0060)
|
||||
#define GVI_COLOR_BAR_HTIMING0 HOSTREG(0x0070)
|
||||
#define GVI_COLOR_BAR_HTIMING1 HOSTREG(0x0074)
|
||||
#define GVI_COLOR_BAR_VTIMING0 HOSTREG(0x0078)
|
||||
#define GVI_COLOR_BAR_VTIMING1 HOSTREG(0x007c)
|
||||
|
||||
/* SYS_CTRL0 */
|
||||
#define SYS_CTRL0_GVI_EN BIT(0)
|
||||
#define SYS_CTRL0_AUTO_GATING BIT(1)
|
||||
#define SYS_CTRL0_FRM_RST_EN BIT(2)
|
||||
#define SYS_CTRL0_FRM_RST_MODE BIT(3)
|
||||
#define SYS_CTRL0_LANE_NUM_MASK GENMASK(7, 4)
|
||||
#define SYS_CTRL0_LANE_NUM(x) UPDATE(x, 7, 4)
|
||||
#define SYS_CTRL0_BYTE_MODE_MASK GENMASK(9, 8)
|
||||
#define SYS_CTRL0_BYTE_MODE(x) UPDATE(x, 9, 8)
|
||||
#define SYS_CTRL0_SECTION_NUM_MASK GENMASK(11, 10)
|
||||
#define SYS_CTRL0_SECTION_NUM(x) UPDATE(x, 11, 10)
|
||||
#define SYS_CTRL0_CDR_ENDIAN_SWAP BIT(12)
|
||||
#define SYS_CTRL0_PACK_BYTE_SWAP BIT(13)
|
||||
#define SYS_CTRL0_PACK_ENDIAN_SWAP BIT(14)
|
||||
#define SYS_CTRL0_ENC8B10B_ENDIAN_SWAP BIT(15)
|
||||
#define SYS_CTRL0_CDR_EN BIT(16)
|
||||
#define SYS_CTRL0_ALN_EN BIT(17)
|
||||
#define SYS_CTRL0_NOR_EN BIT(18)
|
||||
#define SYS_CTRL0_ALN_NOR_MODE BIT(19)
|
||||
#define SYS_CTRL0_GVI_MASK GENMASK(19, 16)
|
||||
#define SYS_CTRL0_GVI_GN_EN(x) UPDATE(x, 19, 16)
|
||||
|
||||
#define SYS_CTRL0_SCRAMBLER_EN BIT(20)
|
||||
#define SYS_CTRL0_ENCODE8B10B_EN BIT(21)
|
||||
#define SYS_CTRL0_INIT_RD_EN BIT(22)
|
||||
#define SYS_CTRL0_INIT_RD_VALUE BIT(23)
|
||||
#define SYS_CTRL0_FORCE_HTPDN_EN BIT(24)
|
||||
#define SYS_CTRL0_FORCE_HTPDN_VALUE BIT(25)
|
||||
#define SYS_CTRL0_FORCE_PLL_EN BIT(26)
|
||||
#define SYS_CTRL0_FORCE_PLL_VALUE BIT(27)
|
||||
#define SYS_CTRL0_FORCE_LOCKN_EN BIT(28)
|
||||
#define SYS_CTRL0_FORCE_LOCKN_VALUE BIT(29)
|
||||
|
||||
/* SYS_CTRL1 */
|
||||
#define SYS_CTRL1_COLOR_DEPTH_MASK GENMASK(3, 0)
|
||||
#define SYS_CTRL1_COLOR_DEPTH(x) UPDATE(x, 3, 0)
|
||||
#define SYS_CTRL1_DUAL_PIXEL_EN BIT(4)
|
||||
#define SYS_CTRL1_TIMING_ALIGN_EN BIT(8)
|
||||
#define SYS_CTRL1_LANE_ALIGN_EN BIT(9)
|
||||
|
||||
#define SYS_CTRL1_DUAL_PIXEL_SWAP BIT(12)
|
||||
#define SYS_CTRL1_RB_SWAP BIT(13)
|
||||
#define SYS_CTRL1_YC_SWAP BIT(14)
|
||||
#define SYS_CTRL1_WHOLE_FRM_EN BIT(16)
|
||||
#define SYS_CTRL1_NOR_PROTECT BIT(17)
|
||||
#define SYS_CTRL1_RD_WCNT_UPDATE BIT(31)
|
||||
|
||||
/* SYS_CTRL2 */
|
||||
#define SYS_CTRL2_AFIFO_READ_THOLD_MASK GENMASK(7, 0)
|
||||
#define SYS_CTRL2_AFIFO_READ_THOLD(x) UPDATE(x, 7, 0)
|
||||
#define SYS_CTRL2_AFIFO_ALMOST_FULL_THOLD_MASK GENMASK(23, 16)
|
||||
#define SYS_CTRL2_AFIFO_ALMOST_FULL_THOLD(x) UPDATE(x, 23, 16)
|
||||
#define SYS_CTRL2_AFIFO_ALMOST_EMPTY_THOLD_MASK GENMASK(31, 24)
|
||||
#define SYS_CTRL2_AFIFO_ALMOST_EMPTY_THOLD(x) UPDATE(x, 31, 24)
|
||||
|
||||
/* SYS_CTRL3 */
|
||||
#define SYS_CTRL3_LANE0_SEL_MASK GENMASK(2, 0)
|
||||
#define SYS_CTRL3_LANE0_SEL(x) UPDATE(x, 2, 0)
|
||||
#define SYS_CTRL3_LANE1_SEL_MASK GENMASK(6, 4)
|
||||
#define SYS_CTRL3_LANE1_SEL(x) UPDATE(x, 6, 4)
|
||||
#define SYS_CTRL3_LANE2_SEL_MASK GENMASK(10, 8)
|
||||
#define SYS_CTRL3_LANE2_SEL(x) UPDATE(x, 10, 8)
|
||||
#define SYS_CTRL3_LANE3_SEL_MASK GENMASK(14, 12)
|
||||
#define SYS_CTRL3_LANE3_SEL(x) UPDATE(x, 14, 12)
|
||||
#define SYS_CTRL3_LANE4_SEL_MASK GENMASK(18, 16)
|
||||
#define SYS_CTRL3_LANE4_SEL(x) UPDATE(x, 18, 16)
|
||||
#define SYS_CTRL3_LANE5_SEL_MASK GENMASK(22, 20)
|
||||
#define SYS_CTRL3_LANE5_SEL(x) UPDATE(x, 22, 20)
|
||||
#define SYS_CTRL3_LANE6_SEL_MASK GENMASK(26, 24)
|
||||
#define SYS_CTRL3_LANE6_SEL(x) UPDATE(x, 26, 24)
|
||||
#define SYS_CTRL3_LANE7_SEL_MASK GENMASK(30, 28)
|
||||
#define SYS_CTRL3_LANE7_SEL(x) UPDATE(x, 30, 28)
|
||||
/* VERSIION */
|
||||
#define VERSION_VERSION(x) UPDATE(x, 31, 0)
|
||||
/* SYS_RESET*/
|
||||
#define SYS_RST_SOFT_RST BIT(0)
|
||||
/* LINE_FLAG */
|
||||
#define LINE_FLAG_LANE_FLAG0_MASK GENMASK(15, 0)
|
||||
#define LINE_FLAG_LANE_FLAG0(x) UPDATE(x, 15, 0)
|
||||
#define LINE_FLAG_LANE_FLAG1_MASK GENMASK(31, 16)
|
||||
#define LINE_FLAG_LANE_FLAG1(x) UPDATE(x, 31, 16)
|
||||
/* STATUS */
|
||||
#define STATUS_HTDPN BIT(4)
|
||||
#define STATUS_LOCKN BIT(5)
|
||||
#define STATUS_PLL_LOCKN BIT(6)
|
||||
#define STATUS_AFIFO0_WCNT_MASK GENMASK(23, 16)
|
||||
#define STATUS_AFIFO0_WCNT(x) UPDATE(x, 23, 16)
|
||||
#define STATUS_AFIFO1_WCNT_MASK GENMASK(31, 24)
|
||||
#define STATUS_AFIFO1_WCNT(x) UPDATE(x, 31, 24)
|
||||
/* PLL_LTIMEOUT */
|
||||
#define PLL_LOCK_TIMEOUT_PLL_LOCK_TIME_OUT_MASK GENMASK(31, 0)
|
||||
#define PLL_LOCK_TIMEOUT_PLL_LOCK_TIME_OUT(x) UPDATE(x, 31, 0)
|
||||
/* HTPDNEOUT */
|
||||
#define HTPDN_TIMEOUT_HTPDN_TIME_OUT_MASK GENMASK(31, 0)
|
||||
#define HTPDN_TIMEOUT_HTPDN_TIME_OUT(x) UPDATE(x, 31, 0)
|
||||
/* LOCKNEOUT */
|
||||
#define LOCKN_TIMEOUT_LOCKN_TIME_OUT_MASK GENMASK(31, 0)
|
||||
#define LOCKN_TIMEOUT_LOCKN_TIME_OUT(x) UPDATE(x, 31, 0)
|
||||
/* WAIT_LOCKN */
|
||||
#define WAIT_LOCKN_WAIT_LOCKN_TIME_MASK GENMASK(30, 0)
|
||||
#define WAIT_LOCKN_WAIT_LOCKN_TIME(x) UPDATE(x, 30, 0)
|
||||
#define WAIT_LOCKN_WAIT_LOCKN_TIME_EN BIT(31)
|
||||
/* WAIT_HTPDN */
|
||||
#define WAIT_HTPDN_WAIT_HTPDN_TIME_MASK GENMASK(30, 0)
|
||||
#define WAIT_HTPDN_WAIT_HTPDN_TIME(x) UPDATE(x, 30, 0)
|
||||
#define WAIT_HTPDN_WAIT_HTPDN_EN BIT(31)
|
||||
/* INTR_EN */
|
||||
#define INTR_EN_INTR_FRM_ST_EN BIT(0)
|
||||
#define INTR_EN_INTR_PLL_LOCK_EN BIT(1)
|
||||
#define INTR_EN_INTR_HTPDN_EN BIT(2)
|
||||
#define INTR_EN_INTR_LOCKN_EN BIT(3)
|
||||
#define INTR_EN_INTR_PLL_TIMEOUT_EN BIT(4)
|
||||
#define INTR_EN_INTR_HTPDN_TIMEOUT_EN BIT(5)
|
||||
#define INTR_EN_INTR_LOCKN_TIMEOUT_EN BIT(6)
|
||||
#define INTR_EN_INTR_LINE_FLAG0_EN BIT(8)
|
||||
#define INTR_EN_INTR_LINE_FLAG1_EN BIT(9)
|
||||
#define INTR_EN_INTR_AFIFO_OVERFLOW_EN BIT(10)
|
||||
#define INTR_EN_INTR_AFIFO_UNDERFLOW_EN BIT(11)
|
||||
#define INTR_EN_INTR_PLL_ERR_EN BIT(12)
|
||||
#define INTR_EN_INTR_HTPDN_ERR_EN BIT(13)
|
||||
#define INTR_EN_INTR_LOCKN_ERR_EN BIT(14)
|
||||
/* INTR_CLR*/
|
||||
#define INTR_CLR_INTR_FRM_ST_CLR BIT(0)
|
||||
#define INTR_CLR_INTR_PLL_LOCK_CLR BIT(1)
|
||||
#define INTR_CLR_INTR_HTPDN_CLR BIT(2)
|
||||
#define INTR_CLR_INTR_LOCKN_CLR BIT(3)
|
||||
#define INTR_CLR_INTR_PLL_TIMEOUT_CLR BIT(4)
|
||||
#define INTR_CLR_INTR_HTPDN_TIMEOUT_CLR BIT(5)
|
||||
#define INTR_CLR_INTR_LOCKN_TIMEOUT_CLR BIT(6)
|
||||
#define INTR_CLR_INTR_LINE_FLAG0_CLR BIT(8)
|
||||
#define INTR_CLR_INTR_LINE_FLAG1_CLR BIT(9)
|
||||
#define INTR_CLR_INTR_AFIFO_OVERFLOW_CLR BIT(10)
|
||||
#define INTR_CLR_INTR_AFIFO_UNDERFLOW_CLR BIT(11)
|
||||
#define INTR_CLR_INTR_PLL_ERR_CLR BIT(12)
|
||||
#define INTR_CLR_INTR_HTPDN_ERR_CLR BIT(13)
|
||||
#define INTR_CLR_INTR_LOCKN_ERR_CLR BIT(14)
|
||||
/* INTR_RAW_STATUS */
|
||||
#define INTR_RAW_STATUS_RAW_INTR_FRM_ST BIT(0)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_PLL_LOCK BIT(1)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_HTPDN BIT(2)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_LOCKN BIT(3)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_PLL_TIMEOUT BIT(4)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_HTPDN_TIMEOUT BIT(5)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_LOCKN_TIMEOUT BIT(6)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_LINE_FLAG0 BIT(8)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_LINE_FLAG1 BIT(9)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_AFIFO_OVERFLOW BIT(10)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_AFIFO_UNDERFLOW BIT(11)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_PLL_ERR BIT(12)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_HTPDN_ERR BIT(13)
|
||||
#define INTR_RAW_STATUS_RAW_INTR_LOCKN_ERR BIT(14)
|
||||
/* INTR_STATUS */
|
||||
#define INTR_STATUS_INTR_FRM_ST BIT(0)
|
||||
#define INTR_STATUS_INTR_PLL_LOCK BIT(1)
|
||||
#define INTR_STATUS_INTR_HTPDN BIT(2)
|
||||
#define INTR_STATUS_INTR_LOCKN BIT(3)
|
||||
#define INTR_STATUS_INTR_PLL_TIMEOUT BIT(4)
|
||||
#define INTR_STATUS_INTR_HTPDN_TIMEOUT BIT(5)
|
||||
#define INTR_STATUS_INTR_LOCKN_TIMEOUT BIT(6)
|
||||
#define INTR_STATUS_INTR_LINE_FLAG0 BIT(8)
|
||||
#define INTR_STATUS_INTR_LINE_FLAG1 BIT(9)
|
||||
#define INTR_STATUS_INTR_AFIFO_OVERFLOW BIT(10)
|
||||
#define INTR_STATUS_INTR_AFIFO_UNDERFLOW BIT(11)
|
||||
#define INTR_STATUS_INTR_PLL_ERR BIT(12)
|
||||
#define INTR_STATUS_INTR_HTPDN_ERR BIT(13)
|
||||
#define INTR_STATUS_INTR_LOCKN_ERR BIT(14)
|
||||
|
||||
/* COLOR_BAR_CTRL */
|
||||
#define COLOR_BAR_EN BIT(0)
|
||||
|
||||
#define COLOR_DEPTH_RGB_YUV444_18BIT 0
|
||||
#define COLOR_DEPTH_RGB_YUV444_24BIT 1
|
||||
#define COLOR_DEPTH_RGB_YUV444_30BIT 2
|
||||
#define COLOR_DEPTH_YUV422_16BIT 8
|
||||
#define COLOR_DEPTH_YUV422_20BIT 9
|
||||
|
||||
enum gvi_byte_mode {
|
||||
GVI_3BYTE_MODE = 0,
|
||||
GVI_4BYTE_MODE,
|
||||
GVI_5BYTE_MODE,
|
||||
};
|
||||
|
||||
struct rk628_gvi {
|
||||
struct drm_bridge base;
|
||||
struct drm_connector connector;
|
||||
struct drm_panel *panel;
|
||||
struct drm_display_mode mode;
|
||||
struct device *dev;
|
||||
struct regmap *grf;
|
||||
struct regmap *regmap;
|
||||
struct clk *pclk;
|
||||
struct reset_control *rst;
|
||||
struct phy *phy;
|
||||
struct rk628 *parent;
|
||||
u32 lane_mbps;
|
||||
u32 bus_format;
|
||||
u32 lane_num;
|
||||
u8 color_depth;
|
||||
u8 byte_mode;
|
||||
bool division_mode;
|
||||
};
|
||||
|
||||
static inline struct rk628_gvi *bridge_to_gvi(struct drm_bridge *b)
|
||||
{
|
||||
return container_of(b, struct rk628_gvi, base);
|
||||
}
|
||||
|
||||
static inline struct rk628_gvi *connector_to_gvi(struct drm_connector *c)
|
||||
{
|
||||
return container_of(c, struct rk628_gvi, connector);
|
||||
}
|
||||
|
||||
static struct drm_encoder *rk628_gvi_connector_best_encoder(struct drm_connector
|
||||
*connector)
|
||||
{
|
||||
struct rk628_gvi *gvi = connector_to_gvi(connector);
|
||||
|
||||
return gvi->base.encoder;
|
||||
}
|
||||
|
||||
static int rk628_gvi_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct rk628_gvi *gvi = connector_to_gvi(connector);
|
||||
struct drm_display_info *info = &connector->display_info;
|
||||
int num_modes;
|
||||
|
||||
num_modes = drm_panel_get_modes(gvi->panel, connector);
|
||||
|
||||
if (info->num_bus_formats)
|
||||
gvi->bus_format = info->bus_formats[0];
|
||||
else
|
||||
gvi->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
|
||||
switch (gvi->bus_format) {
|
||||
case MEDIA_BUS_FMT_RGB666_1X18:
|
||||
gvi->byte_mode = 3;
|
||||
gvi->color_depth = COLOR_DEPTH_RGB_YUV444_18BIT;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_RGB888_1X24:
|
||||
gvi->byte_mode = 4;
|
||||
gvi->color_depth = COLOR_DEPTH_RGB_YUV444_24BIT;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_RGB101010_1X30:
|
||||
gvi->byte_mode = 4;
|
||||
gvi->color_depth = COLOR_DEPTH_RGB_YUV444_30BIT;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_YUYV8_1X16:
|
||||
gvi->byte_mode = 3;
|
||||
gvi->color_depth = COLOR_DEPTH_YUV422_16BIT;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_YUYV10_1X20:
|
||||
gvi->byte_mode = 3;
|
||||
gvi->color_depth = COLOR_DEPTH_YUV422_20BIT;
|
||||
break;
|
||||
default:
|
||||
gvi->byte_mode = 3;
|
||||
gvi->color_depth = COLOR_DEPTH_RGB_YUV444_24BIT;
|
||||
dev_info(gvi->dev, "unsupported bus_format: 0x%x\n",
|
||||
gvi->bus_format);
|
||||
break;
|
||||
}
|
||||
|
||||
info->edid_hdmi_rgb444_dc_modes = 0;
|
||||
info->edid_hdmi_ycbcr444_dc_modes = 0;
|
||||
info->hdmi.y420_dc_modes = 0;
|
||||
info->color_formats = 0;
|
||||
info->max_tmds_clock = 300000;
|
||||
connector->ycbcr_420_allowed = true;
|
||||
|
||||
num_modes += rk628_scaler_add_src_mode(gvi->parent, connector);
|
||||
|
||||
return num_modes;
|
||||
}
|
||||
|
||||
static const
|
||||
struct drm_connector_helper_funcs rk628_gvi_connector_helper_funcs = {
|
||||
.get_modes = rk628_gvi_connector_get_modes,
|
||||
.best_encoder = rk628_gvi_connector_best_encoder,
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
rk628_gvi_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
static void rk628_gvi_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs rk628_gvi_connector_funcs = {
|
||||
.detect = rk628_gvi_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = rk628_gvi_connector_destroy,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static unsigned int rk628_gvi_get_lane_rate(struct rk628_gvi *gvi)
|
||||
{
|
||||
struct device *dev = gvi->dev;
|
||||
const struct drm_display_mode *mode = &gvi->mode;
|
||||
u32 lane_bit_rate, min_lane_rate = 500000, max_lane_rate = 4000000;
|
||||
u64 total_bw;
|
||||
|
||||
/* optional override of the desired bandwidth */
|
||||
if (!of_property_read_u32
|
||||
(dev->of_node, "rockchip,lane-rate", &lane_bit_rate))
|
||||
return lane_bit_rate;
|
||||
|
||||
/**
|
||||
* [ENCODER TOTAL BIT-RATE](bps) = [byte mode](byte) x 10 / [pixel clock](HZ)
|
||||
*
|
||||
* lane_bit_rate = [total bit-rate](bps) / [lane number]
|
||||
*
|
||||
* 500Mbps <= lane_bit_rate <= 4Gbps
|
||||
*/
|
||||
total_bw = (unsigned long long)gvi->byte_mode * 10 * mode->clock; /* Kbps */
|
||||
do_div(total_bw, gvi->lane_num);
|
||||
lane_bit_rate = total_bw;
|
||||
|
||||
if (lane_bit_rate < min_lane_rate)
|
||||
lane_bit_rate = min_lane_rate;
|
||||
if (lane_bit_rate > max_lane_rate)
|
||||
lane_bit_rate = max_lane_rate;
|
||||
|
||||
return lane_bit_rate;
|
||||
}
|
||||
|
||||
static void rk628_gvi_enable_color_bar(struct rk628_gvi *gvi)
|
||||
{
|
||||
const struct drm_display_mode *mode = &gvi->mode;
|
||||
struct videomode vm;
|
||||
u16 hsync_len, hact_st, hact_end, htotal;
|
||||
u16 vsync_len, vact_st, vact_end, vtotal;
|
||||
|
||||
drm_display_mode_to_videomode(mode, &vm);
|
||||
|
||||
if (gvi->division_mode) {
|
||||
hsync_len = vm.hsync_len / 2;
|
||||
hact_st = (vm.hsync_len + vm.hback_porch) / 2;
|
||||
hact_end = (vm.hsync_len + vm.hback_porch + vm.hactive) / 2;
|
||||
htotal = mode->htotal / 2;
|
||||
} else {
|
||||
hsync_len = vm.hsync_len;
|
||||
hact_st = vm.hsync_len + vm.hback_porch;
|
||||
hact_end = vm.hsync_len + vm.hback_porch + vm.hactive;
|
||||
htotal = mode->htotal;
|
||||
}
|
||||
vsync_len = vm.vsync_len;
|
||||
vact_st = vsync_len + vm.vback_porch;
|
||||
vact_end = vact_st + vm.vactive;
|
||||
vtotal = mode->vtotal;
|
||||
|
||||
regmap_write(gvi->regmap, GVI_COLOR_BAR_HTIMING0,
|
||||
hact_st << 16 | hsync_len);
|
||||
regmap_write(gvi->regmap, GVI_COLOR_BAR_HTIMING1,
|
||||
(htotal - 1) << 16 | hact_end);
|
||||
regmap_write(gvi->regmap, GVI_COLOR_BAR_VTIMING0,
|
||||
vact_st << 16 | vsync_len);
|
||||
regmap_write(gvi->regmap, GVI_COLOR_BAR_VTIMING1,
|
||||
(vtotal - 1) << 16 | vact_end);
|
||||
regmap_write_bits(gvi->regmap, GVI_COLOR_BAR_CTRL, COLOR_BAR_EN, 0);
|
||||
}
|
||||
|
||||
static void rk628_gvi_pre_enable(struct rk628_gvi *gvi)
|
||||
{
|
||||
clk_prepare_enable(gvi->pclk);
|
||||
|
||||
/* gvi reset */
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_RST, SYS_RST_SOFT_RST,
|
||||
SYS_RST_SOFT_RST);
|
||||
udelay(10);
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_RST, SYS_RST_SOFT_RST, 0);
|
||||
udelay(10);
|
||||
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_CTRL0, SYS_CTRL0_LANE_NUM_MASK,
|
||||
SYS_CTRL0_LANE_NUM(gvi->lane_num - 1));
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_CTRL0, SYS_CTRL0_BYTE_MODE_MASK,
|
||||
SYS_CTRL0_BYTE_MODE(gvi->byte_mode ==
|
||||
3 ? 0 : (gvi->byte_mode ==
|
||||
4 ? 1 : 2)));
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_CTRL0,
|
||||
SYS_CTRL0_SECTION_NUM_MASK,
|
||||
SYS_CTRL0_SECTION_NUM(gvi->division_mode));
|
||||
regmap_update_bits(gvi->grf, GRF_POST_PROC_CON, SW_SPLIT_EN,
|
||||
gvi->division_mode ? SW_SPLIT_EN : 0);
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_CTRL1, SYS_CTRL1_DUAL_PIXEL_EN,
|
||||
gvi->division_mode ? SYS_CTRL1_DUAL_PIXEL_EN : 0);
|
||||
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_CTRL0, SYS_CTRL0_FRM_RST_EN, 0);
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_CTRL1, SYS_CTRL1_LANE_ALIGN_EN, 0);
|
||||
}
|
||||
|
||||
static void rk628_gvi_post_enable(struct rk628_gvi *gvi)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = SYS_CTRL0_GVI_EN | SYS_CTRL0_AUTO_GATING;
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_CTRL0, val, 3);
|
||||
}
|
||||
|
||||
static void rk628_gvi_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_gvi *gvi = bridge_to_gvi(bridge);
|
||||
unsigned int rate = rk628_gvi_get_lane_rate(gvi);
|
||||
int ret;
|
||||
|
||||
regmap_update_bits(gvi->grf, GRF_SYSTEM_CON0, SW_OUTPUT_MODE_MASK,
|
||||
SW_OUTPUT_MODE(OUTPUT_MODE_GVI));
|
||||
phy_set_bus_width(gvi->phy, rate);
|
||||
rk628_combtxphy_set_gvi_division_mode(gvi->phy, gvi->division_mode);
|
||||
ret = phy_set_mode(gvi->phy, 0);
|
||||
if (ret) {
|
||||
dev_err(gvi->dev, "failed to set phy mode: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
phy_power_on(gvi->phy);
|
||||
gvi->lane_mbps = phy_get_bus_width(gvi->phy);
|
||||
rk628_gvi_pre_enable(gvi);
|
||||
drm_panel_prepare(gvi->panel);
|
||||
rk628_gvi_enable_color_bar(gvi);
|
||||
rk628_gvi_post_enable(gvi);
|
||||
drm_panel_enable(gvi->panel);
|
||||
|
||||
dev_info(gvi->dev,
|
||||
"GVI-Link bandwidth: %d x %d Mbps, Byte mode: %d, Color Depty: %d, %s division mode\n",
|
||||
gvi->lane_mbps, gvi->lane_num, gvi->byte_mode,
|
||||
gvi->color_depth, gvi->division_mode ? "two" : "one");
|
||||
}
|
||||
|
||||
static void rk628_gvi_post_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_gvi *gvi = bridge_to_gvi(bridge);
|
||||
|
||||
regmap_write_bits(gvi->regmap, GVI_SYS_CTRL0, SYS_CTRL0_GVI_EN, 0);
|
||||
}
|
||||
|
||||
static void rk628_gvi_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_gvi *gvi = bridge_to_gvi(bridge);
|
||||
|
||||
drm_panel_disable(gvi->panel);
|
||||
drm_panel_unprepare(gvi->panel);
|
||||
rk628_gvi_post_disable(bridge);
|
||||
clk_disable_unprepare(gvi->pclk);
|
||||
phy_power_off(gvi->phy);
|
||||
}
|
||||
|
||||
static int rk628_gvi_bridge_attach(struct drm_bridge *bridge,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
{
|
||||
struct rk628_gvi *gvi = bridge_to_gvi(bridge);
|
||||
struct drm_connector *connector = &gvi->connector;
|
||||
struct drm_device *drm = bridge->dev;
|
||||
int ret;
|
||||
|
||||
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
|
||||
return 0;
|
||||
|
||||
ret = drm_connector_init(drm, connector, &rk628_gvi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
if (ret) {
|
||||
dev_err(gvi->dev, "Failed to initialize connector with drm\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_connector_helper_add(connector, &rk628_gvi_connector_helper_funcs);
|
||||
drm_connector_attach_encoder(connector, bridge->encoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk628_gvi_bridge_mode_set(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adj)
|
||||
{
|
||||
struct rk628_gvi *gvi = bridge_to_gvi(bridge);
|
||||
|
||||
rk628_mode_copy(gvi->parent, &gvi->mode, mode);
|
||||
|
||||
dev_info(gvi->dev, "src mode: %dx%d, clk: %d, dst mode: %dx%d, clk: %d\n",
|
||||
mode->hdisplay, mode->vdisplay, mode->clock,
|
||||
gvi->mode.hdisplay, gvi->mode.vdisplay, gvi->mode.clock);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs rk628_gvi_bridge_funcs = {
|
||||
.attach = rk628_gvi_bridge_attach,
|
||||
.enable = rk628_gvi_bridge_enable,
|
||||
.disable = rk628_gvi_bridge_disable,
|
||||
.mode_set = rk628_gvi_bridge_mode_set,
|
||||
};
|
||||
|
||||
static const struct regmap_range rk628_gvi_readable_ranges[] = {
|
||||
regmap_reg_range(GVI_SYS_CTRL0, GVI_COLOR_BAR_VTIMING1),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table rk628_gvi_readable_table = {
|
||||
.yes_ranges = rk628_gvi_readable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(rk628_gvi_readable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config rk628_gvi_regmap_cfg = {
|
||||
.name = "gvi",
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = GVI_COLOR_BAR_VTIMING1,
|
||||
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.rd_table = &rk628_gvi_readable_table,
|
||||
};
|
||||
|
||||
static int rk628_gvi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rk628_gvi *gvi;
|
||||
int ret = 0;
|
||||
|
||||
if (!of_device_is_available(dev->of_node))
|
||||
return -ENODEV;
|
||||
|
||||
gvi = devm_kzalloc(dev, sizeof(*gvi), GFP_KERNEL);
|
||||
if (!gvi)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1,
|
||||
&gvi->panel, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gvi->dev = dev;
|
||||
gvi->parent = rk628;
|
||||
gvi->division_mode = of_property_read_bool(dev->of_node,
|
||||
"rockchip,division-mode");
|
||||
ret = of_property_read_u32(dev->of_node, "rockchip,lane-num",
|
||||
&gvi->lane_num);
|
||||
if (ret) {
|
||||
dev_err(gvi->dev, "Failed to get lane num\n");
|
||||
gvi->lane_num = 4;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, gvi);
|
||||
gvi->grf = rk628->grf;
|
||||
if (!gvi->grf)
|
||||
return -ENODEV;
|
||||
|
||||
gvi->regmap = devm_regmap_init_i2c(rk628->client,
|
||||
&rk628_gvi_regmap_cfg);
|
||||
if (IS_ERR(gvi->regmap)) {
|
||||
ret = PTR_ERR(gvi->regmap);
|
||||
dev_err(dev, "failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gvi->pclk = devm_clk_get(dev, "pclk");
|
||||
if (IS_ERR(gvi->pclk)) {
|
||||
ret = PTR_ERR(gvi->pclk);
|
||||
dev_err(dev, "failed to get pclk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gvi->rst = of_reset_control_get(dev->of_node, NULL);
|
||||
if (IS_ERR(gvi->rst)) {
|
||||
ret = PTR_ERR(gvi->rst);
|
||||
dev_err(dev, "failed to get reset control: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gvi->phy = devm_of_phy_get(dev, dev->of_node, NULL);
|
||||
if (IS_ERR(gvi->phy)) {
|
||||
ret = PTR_ERR(gvi->phy);
|
||||
dev_err(dev, "failed to get phy: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gvi->base.funcs = &rk628_gvi_bridge_funcs;
|
||||
gvi->base.of_node = dev->of_node;
|
||||
drm_bridge_add(&gvi->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk628_gvi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628_gvi *gvi = platform_get_drvdata(pdev);
|
||||
|
||||
drm_bridge_remove(&gvi->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rk628_gvi_of_match[] = {
|
||||
{.compatible = "rockchip,rk628-gvi",},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, rk628_gvi_of_match);
|
||||
|
||||
static struct platform_driver rk628_gvi_driver = {
|
||||
.driver = {
|
||||
.name = "rk628-gvi",
|
||||
.of_match_table = of_match_ptr(rk628_gvi_of_match),
|
||||
},
|
||||
.probe = rk628_gvi_probe,
|
||||
.remove = rk628_gvi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(rk628_gvi_driver);
|
||||
|
||||
MODULE_AUTHOR("Sandy Huang <hjc@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Rockchip RK628 GVI driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,980 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Algea Cao <algea.cao@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mfd/rk628.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
|
||||
#define REG(x) ((x) + 0x30000)
|
||||
#define HDMI_RX_HDMI_SETUP_CTRL REG(0x0000)
|
||||
#define HOT_PLUG_DETECT_MASK BIT(0)
|
||||
#define HOT_PLUG_DETECT(x) UPDATE(x, 0, 0)
|
||||
#define HDMI_RX_HDMI_OVR_CTRL REG(0x0004)
|
||||
#define HDMI_RX_HDMI_TIMER_CTRL REG(0x0008)
|
||||
#define HDMI_RX_HDMI_RES_OVR REG(0x0010)
|
||||
#define HDMI_RX_HDMI_RES_STS REG(0x0014)
|
||||
#define HDMI_RX_HDMI_PLL_CTRL REG(0x0018)
|
||||
#define HDMI_RX_HDMI_PLL_FRQSET1 REG(0x001c)
|
||||
#define HDMI_RX_HDMI_PLL_FRQSET2 REG(0x0020)
|
||||
#define HDMI_RX_HDMI_PLL_PAR1 REG(0x0024)
|
||||
#define HDMI_RX_HDMI_PLL_PAR2 REG(0x0028)
|
||||
#define HDMI_RX_HDMI_PLL_PAR3 REG(0x002c)
|
||||
#define HDMI_RX_HDMI_PLL_LCK_STS REG(0x0030)
|
||||
#define HDMI_RX_HDMI_CLK_CTRL REG(0x0034)
|
||||
#define HDMI_RX_HDMI_PCB_CTRL REG(0x0038)
|
||||
#define SEL_PIXCLKSRC_MASK GENMASK(19, 18)
|
||||
#define SEL_PIXCLKSRC(x) UPDATE(x, 19, 18)
|
||||
#define HDMI_RX_HDMI_PHS_CTR REG(0x0040)
|
||||
#define HDMI_RX_HDMI_PHS_USED REG(0x0044)
|
||||
#define HDMI_RX_HDMI_MISC_CTRL REG(0x0048)
|
||||
#define HDMI_RX_HDMI_EQOFF_CTRL REG(0x004c)
|
||||
#define HDMI_RX_HDMI_EQGAIN_CTRL REG(0x0050)
|
||||
#define HDMI_RX_HDMI_EQCAL_STS REG(0x0054)
|
||||
#define HDMI_RX_HDMI_EQRESULT REG(0x0058)
|
||||
#define HDMI_RX_HDMI_EQ_MEAS_CTRL REG(0x005c)
|
||||
#define HDMI_RX_HDMI_WR_CFG REG(0x0060)
|
||||
#define HDMI_RX_HDMI_CTRL REG(0x0064)
|
||||
#define HDMI_RX_HDMI_MODE_RECOVER REG(0x0080)
|
||||
#define PREAMBLE_CNT_LIMIT_MASK GENMASK(31, 27)
|
||||
#define PREAMBLE_CNT_LIMIT(x) UPDATE(x, 31, 27)
|
||||
#define OESSCTL3_THR_MASK GENMASK(20, 19)
|
||||
#define OESSCTL3_THR(x) UPDATE(x, 20, 19)
|
||||
#define SPIKE_FILTER_EN_MASK BIT(18)
|
||||
#define SPIKE_FILTER_EN(x) UPDATE(x, 18, 18)
|
||||
#define DVI_MODE_HYST_MASK GENMASK(17, 13)
|
||||
#define DVI_MODE_HYST(x) UPDATE(x, 17, 13)
|
||||
#define HDMI_MODE_HYST_MASK GENMASK(12, 8)
|
||||
#define HDMI_MODE_HYST(x) UPDATE(x, 12, 8)
|
||||
#define HDMI_MODE_MASK GENMASK(7, 6)
|
||||
#define HDMI_MODE(x) UPDATE(x, 7, 6)
|
||||
#define GB_DET_MASK GENMASK(5, 4)
|
||||
#define GB_DET(x) UPDATE(x, 5, 4)
|
||||
#define EESS_OESS_MASK GENMASK(3, 2)
|
||||
#define EESS_OESS(x) UPDATE(x, 3, 2)
|
||||
#define SEL_CTL01_MASK GENMASK(1, 0)
|
||||
#define SEL_CTL01(x) UPDATE(x, 1, 0)
|
||||
#define HDMI_RX_HDMI_ERROR_PROTECT REG(0x0084)
|
||||
#define RG_BLOCK_OFF_MASK BIT(20)
|
||||
#define RG_BLOCK_OFF(x) UPDATE(x, 20, 20)
|
||||
#define BLOCK_OFF_MASK BIT(19)
|
||||
#define BLOCK_OFF(x) UPDATE(x, 19, 19)
|
||||
#define VALID_MODE_MASK GENMASK(18, 16)
|
||||
#define VALID_MODE(x) UPDATE(x, 18, 16)
|
||||
#define CTRL_FILT_SEN_MASK GENMASK(13, 12)
|
||||
#define CTRL_FILT_SEN(x) UPDATE(x, 13, 12)
|
||||
#define VS_FILT_SENS_MASK GENMASK(11, 10)
|
||||
#define VS_FILT_SENS(x) UPDATE(x, 11, 10)
|
||||
#define HS_FILT_SENS_MASK GENMASK(9, 8)
|
||||
#define HS_FILT_SENS(x) UPDATE(x, 9, 8)
|
||||
#define DE_MEASURE_MODE_MASK GENMASK(7, 6)
|
||||
#define DE_MEASURE_MODE(x) UPDATE(x, 7, 6)
|
||||
#define DE_REGEN_MASK BIT(5)
|
||||
#define DE_REGEN(x) UPDATE(x, 5, 5)
|
||||
#define DE_FILTER_SENS_MASK GENMASK(4, 3)
|
||||
#define DE_FILTER_SENS(x) UPDATE(x, 4, 3)
|
||||
#define HDMI_RX_HDMI_ERD_STS REG(0x0088)
|
||||
#define HDMI_RX_HDMI_SYNC_CTRL REG(0x0090)
|
||||
#define VS_POL_ADJ_MODE_MASK GENMASK(4, 3)
|
||||
#define VS_POL_ADJ_MODE(x) UPDATE(x, 4, 3)
|
||||
#define HS_POL_ADJ_MODE_MASK GENMASK(2, 1)
|
||||
#define HS_POL_ADJ_MODE(x) UPDATE(x, 2, 1)
|
||||
#define HDMI_RX_HDMI_CKM_EVLTM REG(0x0094)
|
||||
#define LOCK_HYST_MASK GENMASK(21, 20)
|
||||
#define LOCK_HYST(x) UPDATE(x, 21, 20)
|
||||
#define CLK_HYST_MASK GENMASK(18, 16)
|
||||
#define CLK_HYST(x) UPDATE(x, 18, 16)
|
||||
#define EVAL_TIME_MASK GENMASK(15, 4)
|
||||
#define EVAL_TIME(x) UPDATE(x, 15, 4)
|
||||
#define HDMI_RX_HDMI_CKM_F REG(0x0098)
|
||||
#define HDMIRX_MAXFREQ_MASK GENMASK(31, 16)
|
||||
#define HDMIRX_MAXFREQ(x) UPDATE(x, 31, 16)
|
||||
#define MINFREQ_MASK GENMASK(15, 0)
|
||||
#define MINFREQ(x) UPDATE(x, 15, 0)
|
||||
#define HDMI_RX_HDMI_CKM_RESULT REG(0x009c)
|
||||
#define HDMI_RX_HDMI_PVO_CONFIG REG(0x00a0)
|
||||
#define HDMI_RX_HDMI_RESMPL_CTRL REG(0x00a4)
|
||||
#define MAN_VID_DEREPEAT_MASK GENMASK(4, 1)
|
||||
#define MAN_VID_DEREPEAT(x) UPDATE(x, 4, 1)
|
||||
#define AUTO_DEREPEAT_MASK BIT(0)
|
||||
#define AUTO_DEREPEAT(x) UPDATE(x, 0, 0)
|
||||
#define HDMI_RX_HDMI_DCM_CTRL REG(0x00a8)
|
||||
#define DCM_DEFAULT_PHASE_MASK BIT(18)
|
||||
#define DCM_DEFAULT_PHASE(x) UPDATE(x, 18, 18)
|
||||
#define DCM_COLOUR_DEPTH_SEL_MASK BIT(12)
|
||||
#define DCM_COLOUR_DEPTH_SEL(x) UPDATE(x, 12, 12)
|
||||
#define DCM_COLOUR_DEPTH_MASK GENMASK(11, 8)
|
||||
#define DCM_COLOUR_DEPTH(x) UPDATE(x, 11, 8)
|
||||
#define DCM_GCP_ZERO_FIELDS_MASK GENMASK(5, 2)
|
||||
#define DCM_GCP_ZERO_FIELDS(x) UPDATE(x, 5, 2)
|
||||
#define HDMI_RX_HDMI_VM_CFG_CH_0_1 REG(0x00b0)
|
||||
#define HDMI_RX_HDMI_VM_CFG_CH2 REG(0x00b4)
|
||||
#define HDMI_RX_HDMI_SPARE REG(0x00b8)
|
||||
#define HDMI_RX_HDMI_STS REG(0x00bc)
|
||||
#define HDMI_RX_HDCP_CTRL REG(0x00c0)
|
||||
#define HDCP_ENABLE_MASK BIT(24)
|
||||
#define HDCP_ENABLE(x) UPDATE(x, 24, 24)
|
||||
#define FREEZE_HDCP_FSM_MASK BIT(21)
|
||||
#define FREEZE_HDCP_FSM(x) UPDATE(x, 21, 21)
|
||||
#define FREEZE_HDCP_STATE_MASK GENMASK(20, 15)
|
||||
#define FREEZE_HDCP_STATE(x) UPDATE(x, 20, 15)
|
||||
#define HDCP_CTL_MASK GENMASK(9, 8)
|
||||
#define HDCP_CTL(x) UPDATE(x, 9, 8)
|
||||
#define HDCP_RI_RATE_MASK GENMASK(7, 6)
|
||||
#define HDCP_RI_RATE(x) UPDATE(x, 7, 6)
|
||||
#define KEY_DECRYPT_ENABLE_MASK BIT(1)
|
||||
#define KEY_DECRYPT_ENABLE(x) UPDATE(x, 1, 1)
|
||||
#define HDCP_ENC_EN_MASK BIT(0)
|
||||
#define HDCP_ENC_EN(x) UPDATE(x, 0, 0)
|
||||
#define HDMI_RX_HDCP_SETTINGS REG(0x00c4)
|
||||
#define HDMI_RX_HDCP_SEED REG(0x00c8)
|
||||
#define HDMI_RX_HDCP_BKSV1 REG(0x00cc)
|
||||
#define HDMI_RX_HDCP_BKSV0 REG(0x00d0)
|
||||
#define HDMI_RX_HDCP_KIDX REG(0x00d4)
|
||||
#define HDMI_RX_HDCP_KEY1 REG(0x00d8)
|
||||
#define HDMI_RX_HDCP_KEY0 REG(0x00dc)
|
||||
#define HDMI_RX_HDCP_DBG REG(0x00e0)
|
||||
#define HDMI_RX_HDCP_AKSV1 REG(0x00e4)
|
||||
#define HDMI_RX_HDCP_AKSV0 REG(0x00e8)
|
||||
#define HDMI_RX_HDCP_AN1 REG(0x00ec)
|
||||
#define HDMI_RX_HDCP_AN0 REG(0x00f0)
|
||||
#define HDMI_RX_HDCP_EESS_WOO REG(0x00f4)
|
||||
#define HDMI_RX_HDCP_I2C_TIMEOUT REG(0x00f8)
|
||||
#define HDMI_RX_HDCP_STS REG(0x00fc)
|
||||
#define HDMI_RX_MD_HCTRL1 REG(0x0140)
|
||||
#define HACT_PIX_ITH_MASK GENMASK(10, 8)
|
||||
#define HACT_PIX_ITH(x) UPDATE(x, 10, 8)
|
||||
#define HACT_PIX_SRC_MASK BIT(5)
|
||||
#define HACT_PIX_SRC(x) UPDATE(x, 5, 5)
|
||||
#define HTOT_PIX_SRC_MASK BIT(4)
|
||||
#define HTOT_PIX_SRC(x) UPDATE(x, 4, 4)
|
||||
#define HDMI_RX_MD_HCTRL2 REG(0x0144)
|
||||
#define HS_CLK_ITH_MASK GENMASK(14, 12)
|
||||
#define HS_CLK_ITH(x) UPDATE(x, 14, 12)
|
||||
#define HTOT32_CLK_ITH_MASK GENMASK(9, 8)
|
||||
#define HTOT32_CLK_ITH(x) UPDATE(x, 9, 8)
|
||||
#define VS_ACT_TIME_MASK BIT(5)
|
||||
#define VS_ACT_TIME(x) UPDATE(x, 5, 5)
|
||||
#define HS_ACT_TIME_MASK GENMASK(4, 3)
|
||||
#define HS_ACT_TIME(x) UPDATE(x, 4, 3)
|
||||
#define H_START_POS_MASK GENMASK(1, 0)
|
||||
#define H_START_POS(x) UPDATE(x, 1, 0)
|
||||
#define HDMI_RX_MD_HT0 REG(0x0148)
|
||||
#define HDMI_RX_MD_HT1 REG(0x014c)
|
||||
#define HDMI_RX_MD_HACT_PX REG(0x0150)
|
||||
#define HDMI_RX_MD_HACT_RSV REG(0x0154)
|
||||
#define HDMI_RX_MD_VCTRL REG(0x0158)
|
||||
#define V_OFFS_LIN_MODE_MASK BIT(4)
|
||||
#define V_OFFS_LIN_MODE(x) UPDATE(x, 4, 4)
|
||||
#define V_EDGE_MASK BIT(1)
|
||||
#define V_EDGE(x) UPDATE(x, 1, 1)
|
||||
#define V_MODE_MASK BIT(0)
|
||||
#define V_MODE(x) UPDATE(x, 0, 0)
|
||||
#define HDMI_RX_MD_VSC REG(0x015c)
|
||||
#define HDMI_RX_MD_VTC REG(0x0160)
|
||||
#define HDMI_RX_MD_VOL REG(0x0164)
|
||||
#define HDMI_RX_MD_VAL REG(0x0168)
|
||||
#define HDMI_RX_MD_VTH REG(0x016c)
|
||||
#define VOFS_LIN_ITH_MASK GENMASK(11, 10)
|
||||
#define VOFS_LIN_ITH(x) UPDATE(x, 11, 10)
|
||||
#define VACT_LIN_ITH_MASK GENMASK(9, 8)
|
||||
#define VACT_LIN_ITH(x) UPDATE(x, 9, 8)
|
||||
#define VTOT_LIN_ITH_MASK GENMASK(7, 6)
|
||||
#define VTOT_LIN_ITH(x) UPDATE(x, 7, 6)
|
||||
#define VS_CLK_ITH_MASK GENMASK(5, 3)
|
||||
#define VS_CLK_ITH(x) UPDATE(x, 5, 3)
|
||||
#define VTOT_CLK_ITH_MASK GENMASK(2, 0)
|
||||
#define VTOT_CLK_ITH(x) UPDATE(x, 2, 0)
|
||||
#define HDMI_RX_MD_VTL REG(0x0170)
|
||||
#define HDMI_RX_MD_IL_CTRL REG(0x0174)
|
||||
#define HDMI_RX_MD_IL_SKEW REG(0x0178)
|
||||
#define HDMI_RX_MD_IL_POL REG(0x017c)
|
||||
#define FAFIELDDET_EN_MASK BIT(2)
|
||||
#define FAFIELDDET_EN(x) UPDATE(x, 2, 2)
|
||||
#define FIELD_POL_MODE_MASK GENMASK(1, 0)
|
||||
#define FIELD_POL_MODE(x) UPDATE(x, 1, 0)
|
||||
#define HDMI_RX_MD_STS REG(0x0180)
|
||||
#define HDMI_RX_AUD_CTRL REG(0x0200)
|
||||
#define HDMI_RX_AUD_PLL_CTRL REG(0x0208)
|
||||
#define PLL_LOCK_TOGGLE_DIV_MASK GENMASK(27, 24)
|
||||
#define PLL_LOCK_TOGGLE_DIV(x) UPDATE(x, 27, 24)
|
||||
#define HDMI_RX_AUD_CLK_CTRL REG(0x0214)
|
||||
#define CTS_N_REF_MASK BIT(4)
|
||||
#define CTS_N_REF(x) UPDATE(x, 4, 4)
|
||||
#define HDMI_RX_AUD_CLK_STS REG(0x023c)
|
||||
#define HDMI_RX_AUD_FIFO_CTRL REG(0x0240)
|
||||
#define AFIF_SUBPACKET_DESEL_MASK GENMASK(27, 24)
|
||||
#define AFIF_SUBPACKET_DESEL(x) UPDATE(x, 27, 24)
|
||||
#define AFIF_SUBPACKETS_MASK BIT(16)
|
||||
#define AFIF_SUBPACKETS(x) UPDATE(x, 16, 16)
|
||||
#define MSA_CHANNEL_DESELECT BIT(24)
|
||||
#define HDMI_RX_AUD_FIFO_TH REG(0x0244)
|
||||
#define AFIF_TH_START_MASK GENMASK(26, 18)
|
||||
#define AFIF_TH_START(x) UPDATE(x, 26, 18)
|
||||
#define AFIF_TH_MAX_MASK GENMASK(17, 9)
|
||||
#define AFIF_TH_MAX(x) UPDATE(x, 17, 9)
|
||||
#define AFIF_TH_MIN_MASK GENMASK(8, 0)
|
||||
#define AFIF_TH_MIN(x) UPDATE(x, 8, 0)
|
||||
#define HDMI_RX_AUD_FIFO_FILL_S REG(0x0248)
|
||||
#define HDMI_RX_AUD_FIFO_CLR_MM REG(0x024c)
|
||||
#define HDMI_RX_AUD_FIFO_FILLSTS REG(0x0250)
|
||||
#define HDMI_RX_AUD_CHEXTR_CTRL REG(0x0254)
|
||||
#define AUD_LAYOUT_CTRL(x) UPDATE(x, 1, 0)
|
||||
#define HDMI_RX_AUD_MUTE_CTRL REG(0x0258)
|
||||
#define APPLY_INT_MUTE_MASK BIT(31)
|
||||
#define APPLY_INT_MUTE(x) UPDATE(x, 31, 31)
|
||||
#define APORT_SHDW_CTRL_MASK GENMASK(22, 21)
|
||||
#define APORT_SHDW_CTRL(x) UPDATE(x, 22, 21)
|
||||
#define AUTO_ACLK_MUTE_MASK GENMASK(20, 19)
|
||||
#define AUTO_ACLK_MUTE(x) UPDATE(x, 20, 19)
|
||||
#define AUD_MUTE_SPEED_MASK GENMASK(16, 10)
|
||||
#define AUD_MUTE_SPEED(x) UPDATE(x, 16, 10)
|
||||
#define AUD_AVMUTE_EN_MASK BIT(7)
|
||||
#define AUD_AVMUTE_EN(x) UPDATE(x, 7, 7)
|
||||
#define AUD_MUTE_SEL_MASK GENMASK(6, 5)
|
||||
#define AUD_MUTE_SEL(x) UPDATE(x, 6, 5)
|
||||
#define AUD_MUTE_MODE_MASK GENMASK(4, 3)
|
||||
#define AUD_MUTE_MODE(x) UPDATE(x, 4, 3)
|
||||
#define HDMI_RX_AUD_FIFO_FILLSTS1 REG(0x025c)
|
||||
#define HDMI_RX_AUD_SAO_CTRL REG(0x0260)
|
||||
#define I2S_LPCM_BPCUV_MASK BIT(11)
|
||||
#define I2S_LPCM_BPCUV(x) UPDATE(x, 11, 11)
|
||||
#define I2S_32_16_MASK BIT(0)
|
||||
#define I2S_32_16(x) UPDATE(x, 0, 0)
|
||||
#define HDMI_RX_AUD_PAO_CTRL REG(0x0264)
|
||||
#define PAO_RATE_MASK GENMASK(17, 16)
|
||||
#define PAO_RATE(x) UPDATE(x, 17, 16)
|
||||
#define HDMI_RX_AUD_SPARE REG(0x0268)
|
||||
#define HDMI_RX_AUD_FIFO_STS REG(0x027c)
|
||||
#define HDMI_RX_AUDPLL_GEN_CTS REG(0x0280)
|
||||
#define AUDPLL_CTS_MANUAL(x) UPDATE(x, 19, 0)
|
||||
#define HDMI_RX_AUDPLL_GEN_N REG(0x0284)
|
||||
#define AUDPLL_N_MANUAL(x) UPDATE(x, 19, 0)
|
||||
#define HDMI_RX_AUDPLL_GEN_CTRL_RW1 REG(0x0288)
|
||||
#define HDMI_RX_AUDPLL_GEN_CTRL_RW2 REG(0x028c)
|
||||
#define HDMI_RX_AUDPLL_GEN_CTRL_W1 REG(0x0298)
|
||||
#define HDMI_RX_AUDPLL_GEN_STS_RO1 REG(0x02a0)
|
||||
#define HDMI_RX_AUDPLL_GEN_STS_RO2 REG(0x02a4)
|
||||
#define HDMI_RX_AUDPLL_SC_NDIVCTSTH REG(0x02a8)
|
||||
#define HDMI_RX_AUDPLL_SC_CTS REG(0x02ac)
|
||||
#define HDMI_RX_AUDPLL_SC_N REG(0x02b0)
|
||||
#define HDMI_RX_AUDPLL_SC_CTRL REG(0x02b4)
|
||||
#define HDMI_RX_AUDPLL_SC_STS1 REG(0x02b8)
|
||||
#define HDMI_RX_AUDPLL_SC_STS2 REG(0x02bc)
|
||||
#define HDMI_RX_SNPS_PHYG3_CTRL REG(0x02c0)
|
||||
#define PORTSELECT_MASK GENMASK(3, 2)
|
||||
#define PORTSELECT(x) UPDATE(x, 3, 2)
|
||||
#define HDMI_RX_I2CM_PHYG3_SLAVE REG(0x02c4)
|
||||
#define HDMI_RX_I2CM_PHYG3_ADDRESS REG(0x02c8)
|
||||
#define HDMI_RX_I2CM_PHYG3_DATAO REG(0x02cc)
|
||||
#define HDMI_RX_I2CM_PHYG3_DATAI REG(0x02d0)
|
||||
#define HDMI_RX_I2CM_PHYG3_OPERATION REG(0x02d4)
|
||||
#define HDMI_RX_I2CM_PHYG3_MODE REG(0x02d8)
|
||||
#define HDMI_RX_I2CM_PHYG3_SOFTRST REG(0x02dc)
|
||||
#define HDMI_RX_I2CM_PHYG3_SS_CNTS REG(0x02e0)
|
||||
#define HDMI_RX_I2CM_PHYG3_FS_HCNT REG(0x02e4)
|
||||
#define HDMI_RX_JTAG_CONF REG(0x02ec)
|
||||
#define HDMI_RX_JTAG_TAP_TCLK REG(0x02f0)
|
||||
#define HDMI_RX_JTAG_TAP_IN REG(0x02f4)
|
||||
#define HDMI_RX_JTAG_TAP_OUT REG(0x02f8)
|
||||
#define HDMI_RX_JTAG_ADDR REG(0x02fc)
|
||||
#define HDMI_RX_PDEC_CTRL REG(0x0300)
|
||||
#define PFIFO_SCORE_FILTER_EN BIT(31)
|
||||
#define PFIFO_SCORE_HDP_IF BIT(29)
|
||||
#define PFIFO_SCORE_AMP_IF BIT(28)
|
||||
#define PFIFO_SCORE_NTSCVBI_IF BIT(27)
|
||||
#define PFIFO_SCORE_MPEGS_IF BIT(26)
|
||||
#define PFIFO_SCORE_AUD_IF BIT(25)
|
||||
#define PFIFO_SCORE_SPD_IF BIT(24)
|
||||
#define PFIFO_SCORE_AVI_IF BIT(23)
|
||||
#define PFIFO_SCORE_VS_IF BIT(22)
|
||||
#define PFIFO_SCORE_GMTP BIT(21)
|
||||
#define PFIFO_SCORE_ISRC2 BIT(20)
|
||||
#define PFIFO_SCORE_ISRC1 BIT(19)
|
||||
#define PFIFO_SCORE_ACP BIT(18)
|
||||
#define PFIFO_SCORE_GCP BIT(17)
|
||||
#define PFIFO_SCORE_ACR BIT(16)
|
||||
#define GCP_GLOBAVMUTE BIT(15)
|
||||
#define PD_FIFO_WE BIT(4)
|
||||
#define PDEC_BCH_EN BIT(0)
|
||||
#define HDMI_RX_PDEC_FIFO_CFG REG(0x0304)
|
||||
#define PD_FIFO_TH_START_MASK GENMASK(29, 20)
|
||||
#define PD_FIFO_TH_START(x) UPDATE(x, 29, 20)
|
||||
#define PD_FIFO_TH_MAX_MASK GENMASK(19, 10)
|
||||
#define PD_FIFO_TH_MAX(x) UPDATE(x, 19, 10)
|
||||
#define PD_FIFO_TH_MIN_MASK GENMASK(9, 0)
|
||||
#define PD_FIFO_TH_MIN(x) UPDATE(x, 9, 0)
|
||||
#define HDMI_RX_PDEC_FIFO_STS REG(0x0308)
|
||||
#define HDMI_RX_PDEC_FIFO_DATA REG(0x030c)
|
||||
#define HDMI_RX_PDEC_AUDIODET_CTRL REG(0x0310)
|
||||
#define AUDIODET_THRESHOLD_MASK GENMASK(13, 9)
|
||||
#define AUDIODET_THRESHOLD(x) UPDATE(x, 13, 9)
|
||||
#define HDMI_RX_PDEC_DBG_ACP REG(0x031c)
|
||||
#define HDMI_RX_PDEC_DBG_ERR_CORR REG(0x0320)
|
||||
#define HDMI_RX_PDEC_FIFO_STS1 REG(0x0324)
|
||||
#define HDMI_RX_PDEC_ACRM_CTRL REG(0x0330)
|
||||
#define DELTACTS_IRQTRIG_MASK GENMASK(4, 2)
|
||||
#define DELTACTS_IRQTRIG(x) UPDATE(x, 4, 2)
|
||||
#define HDMI_RX_PDEC_ACRM_MAX REG(0x0334)
|
||||
#define HDMI_RX_PDEC_ACRM_MIN REG(0x0338)
|
||||
#define HDMI_RX_PDEC_ERR_FILTER REG(0x033c)
|
||||
#define HDMI_RX_PDEC_ASP_CTRL REG(0x0340)
|
||||
#define HDMI_RX_PDEC_ASP_ERR REG(0x0344)
|
||||
#define HDMI_RX_PDEC_STS REG(0x0360)
|
||||
#define HDMI_RX_PDEC_AUD_STS REG(0x0364)
|
||||
#define HDMI_RX_PDEC_VSI_PAYLOAD0 REG(0x0368)
|
||||
#define HDMI_RX_PDEC_VSI_PAYLOAD1 REG(0x036c)
|
||||
#define HDMI_RX_PDEC_VSI_PAYLOAD2 REG(0x0370)
|
||||
#define HDMI_RX_PDEC_VSI_PAYLOAD3 REG(0x0374)
|
||||
#define HDMI_RX_PDEC_VSI_PAYLOAD4 REG(0x0378)
|
||||
#define HDMI_RX_PDEC_VSI_PAYLOAD5 REG(0x037c)
|
||||
#define HDMI_RX_PDEC_GCP_AVMUTE REG(0x0380)
|
||||
#define PKTDEC_GCP_CD_MASK GENMASK(7, 4)
|
||||
#define HDMI_RX_PDEC_ACR_CTS REG(0x0390)
|
||||
#define HDMI_RX_PDEC_ACR_N REG(0x0394)
|
||||
#define HDMI_RX_PDEC_AVI_HB REG(0x03a0)
|
||||
#define HDMI_RX_PDEC_AVI_PB REG(0x03a4)
|
||||
#define VID_IDENT_CODE_VIC7 BIT(31)
|
||||
#define VID_IDENT_CODE GENMASK(30, 24)
|
||||
#define VIDEO_FORMAT GENMASK(6, 5)
|
||||
#define HDMI_RX_PDEC_AVI_TBB REG(0x03a8)
|
||||
#define HDMI_RX_PDEC_AVI_LRB REG(0x03ac)
|
||||
#define HDMI_RX_PDEC_AIF_CTRL REG(0x03c0)
|
||||
#define FC_LFE_EXCHG BIT(18)
|
||||
#define HDMI_RX_PDEC_AIF_HB REG(0x03c4)
|
||||
#define HDMI_RX_PDEC_AIF_PB0 REG(0x03c8)
|
||||
#define HDMI_RX_PDEC_AIF_PB1 REG(0x03cc)
|
||||
#define HDMI_RX_PDEC_GMD_HB REG(0x03d0)
|
||||
#define HDMI_RX_PDEC_GMD_PB REG(0x03d4)
|
||||
#define HDMI_RX_PDEC_VSI_ST0 REG(0x03e0)
|
||||
#define HDMI_RX_PDEC_VSI_ST1 REG(0x03e4)
|
||||
#define HDMI_RX_PDEC_VSI_PB0 REG(0x03e8)
|
||||
#define HDMI_RX_PDEC_VSI_PB1 REG(0x03ec)
|
||||
#define HDMI_RX_PDEC_VSI_PB2 REG(0x03f0)
|
||||
#define HDMI_RX_PDEC_VSI_PB3 REG(0x03f4)
|
||||
#define HDMI_RX_PDEC_VSI_PB4 REG(0x03f8)
|
||||
#define HDMI_RX_PDEC_VSI_PB5 REG(0x03fc)
|
||||
#define HDMI_RX_CEAVID_CONFIG REG(0x0400)
|
||||
#define HDMI_RX_CEAVID_3DCONFIG REG(0x0404)
|
||||
#define HDMI_RX_CEAVID_HCONFIG_LO REG(0x0408)
|
||||
#define HDMI_RX_CEAVID_HCONFIG_HI REG(0x040c)
|
||||
#define HDMI_RX_CEAVID_VCONFIG_LO REG(0x0410)
|
||||
#define HDMI_RX_CEAVID_VCONFIG_HI REG(0x0414)
|
||||
#define HDMI_RX_CEAVID_STATUS REG(0x0418)
|
||||
#define HDMI_RX_PDEC_AMP_HB REG(0x0480)
|
||||
#define HDMI_RX_PDEC_AMP_PAYLOAD0 REG(0x0484)
|
||||
#define HDMI_RX_PDEC_AMP_PAYLOAD1 REG(0x0488)
|
||||
#define HDMI_RX_PDEC_AMP_PAYLOAD2 REG(0x048c)
|
||||
#define HDMI_RX_PDEC_AMP_PAYLOAD3 REG(0x0490)
|
||||
#define HDMI_RX_PDEC_AMP_PAYLOAD4 REG(0x0494)
|
||||
#define HDMI_RX_PDEC_AMP_PAYLOAD5 REG(0x0498)
|
||||
#define HDMI_RX_PDEC_AMP_PAYLOAD6 REG(0x049c)
|
||||
#define HDMI_RX_PDEC_NTSCVBI_HB REG(0x04a0)
|
||||
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD0 REG(0x04a4)
|
||||
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD1 REG(0x04a8)
|
||||
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD2 REG(0x04ac)
|
||||
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD3 REG(0x04b0)
|
||||
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD4 REG(0x04b4)
|
||||
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD5 REG(0x04b8)
|
||||
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD6 REG(0x04bc)
|
||||
#define HDMI_RX_PDEC_DRM_HB REG(0x04c0)
|
||||
#define HDMI_RX_PDEC_DRM_PAYLOAD0 REG(0x04c4)
|
||||
#define HDMI_RX_PDEC_DRM_PAYLOAD1 REG(0x04c8)
|
||||
#define HDMI_RX_PDEC_DRM_PAYLOAD2 REG(0x04cc)
|
||||
#define HDMI_RX_PDEC_DRM_PAYLOAD3 REG(0x04d0)
|
||||
#define HDMI_RX_PDEC_DRM_PAYLOAD4 REG(0x04d4)
|
||||
#define HDMI_RX_PDEC_DRM_PAYLOAD5 REG(0x04d8)
|
||||
#define HDMI_RX_PDEC_DRM_PAYLOAD6 REG(0x04dc)
|
||||
#define HDMI_RX_MHLMODE_CTRL REG(0x0500)
|
||||
#define HDMI_RX_CDSENSE_STATUS REG(0x0504)
|
||||
#define HDMI_RX_DESERFIFO_CTRL REG(0x0508)
|
||||
#define HDMI_RX_DESER_INTTRSHCTRL REG(0x050c)
|
||||
#define HDMI_RX_DESER_INTCNTCTRL REG(0x0510)
|
||||
#define HDMI_RX_DESER_INTCNT REG(0x0514)
|
||||
#define HDMI_RX_HDCP_RPT_CTRL REG(0x0600)
|
||||
#define HDMI_RX_HDCP_RPT_BSTATUS REG(0x0604)
|
||||
#define HDMI_RX_HDCP_RPT_KSVFIFO_CTRL REG(0x0608)
|
||||
#define HDMI_RX_HDCP_RPT_KSVFIFO1 REG(0x060c)
|
||||
#define HDMI_RX_HDCP_RPT_KSVFIFO0 REG(0x0610)
|
||||
#define HDMI_RX_HDMI20_CONTROL REG(0x0800)
|
||||
#define HDMI_RX_SCDC_I2CCONFIG REG(0x0804)
|
||||
#define I2CSPIKESUPPR_MASK GENMASK(25, 24)
|
||||
#define I2CSPIKESUPPR(x) UPDATE(x, 25, 24)
|
||||
#define HDMI_RX_SCDC_CONFIG REG(0x0808)
|
||||
#define HDMI_RX_CHLOCK_CONFIG REG(0x080c)
|
||||
#define CHLOCKMAXER_MASK GENMASK(29, 20)
|
||||
#define CHLOCKMAXER(x) UPDATE(x, 29, 20)
|
||||
#define MILISECTIMERLIMIT_MASK GENMASK(15, 0)
|
||||
#define MILISECTIMERLIMIT(x) UPDATE(x, 15, 0)
|
||||
#define HDMI_RX_HDCP22_CONTROL REG(0x081c)
|
||||
#define HDMI_RX_SCDC_REGS0 REG(0x0820)
|
||||
#define HDMI_RX_SCDC_REGS1 REG(0x0824)
|
||||
#define HDMI_RX_SCDC_REGS2 REG(0x0828)
|
||||
#define HDMI_RX_SCDC_REGS3 REG(0x082c)
|
||||
#define HDMI_RX_SCDC_MANSPEC0 REG(0x0840)
|
||||
#define HDMI_RX_SCDC_MANSPEC1 REG(0x0844)
|
||||
#define HDMI_RX_SCDC_MANSPEC2 REG(0x0848)
|
||||
#define HDMI_RX_SCDC_MANSPEC3 REG(0x084c)
|
||||
#define HDMI_RX_SCDC_MANSPEC4 REG(0x0850)
|
||||
#define HDMI_RX_SCDC_WRDATA0 REG(0x0860)
|
||||
#define MANUFACTUREROUI_MASK GENMASK(31, 8)
|
||||
#define MANUFACTUREROUI(x) UPDATE(x, 31, 8)
|
||||
#define SINKVERSION_MASK GENMASK(7, 0)
|
||||
#define SINKVERSION(x) UPDATE(x, 7, 0)
|
||||
#define HDMI_RX_SCDC_WRDATA1 REG(0x0864)
|
||||
#define HDMI_RX_SCDC_WRDATA2 REG(0x0868)
|
||||
#define HDMI_RX_SCDC_WRDATA3 REG(0x086c)
|
||||
#define HDMI_RX_SCDC_WRDATA4 REG(0x0870)
|
||||
#define HDMI_RX_SCDC_WRDATA5 REG(0x0874)
|
||||
#define HDMI_RX_SCDC_WRDATA6 REG(0x0878)
|
||||
#define HDMI_RX_SCDC_WRDATA7 REG(0x087c)
|
||||
#define HDMI_RX_HDMI20_STATUS REG(0x08e0)
|
||||
#define HDMI_RX_HDCP2_ESM_GLOBAL_GPIO_IN REG(0x08e8)
|
||||
#define HDMI_RX_HDCP2_ESM_GLOBAL_GPIO_OUT REG(0x08ec)
|
||||
#define HDMI_RX_HDCP2_ESM_P0_GPIO_IN REG(0x08f0)
|
||||
#define HDMI_RX_HDCP2_ESM_P0_GPIO_OUT REG(0x08f4)
|
||||
#define HDMI_RX_HDCP22_STATUS REG(0x08fc)
|
||||
#define HDMI_RX_HDMI2_IEN_CLR REG(0x0f60)
|
||||
#define HDMI_RX_HDMI2_IEN_SET REG(0x0f64)
|
||||
#define HDMI_RX_HDMI2_ISTS REG(0x0f68)
|
||||
#define HDMI_RX_HDMI2_IEN REG(0x0f6c)
|
||||
#define HDMI_RX_HDMI2_ICLR REG(0x0f70)
|
||||
#define HDMI_RX_HDMI2_ISET REG(0x0f74)
|
||||
#define HDMI_RX_PDEC_IEN_CLR REG(0x0f78)
|
||||
#define HDMI_RX_PDEC_IEN_SET REG(0x0f7c)
|
||||
#define HDMI_RX_PDEC_ISTS REG(0x0f80)
|
||||
#define HDMI_RX_PDEC_IEN REG(0x0f84)
|
||||
#define HDMI_RX_PDEC_ICLR REG(0x0f88)
|
||||
#define HDMI_RX_PDEC_ISET REG(0x0f8c)
|
||||
#define HDMI_RX_AUD_CEC_IEN_CLR REG(0x0f90)
|
||||
#define HDMI_RX_AUD_CEC_IEN_SET REG(0x0f94)
|
||||
#define HDMI_RX_AUD_CEC_ISTS REG(0x0f98)
|
||||
#define HDMI_RX_AUD_CEC_IEN REG(0x0f9c)
|
||||
#define HDMI_RX_AUD_CEC_ICLR REG(0x0fa0)
|
||||
#define HDMI_RX_AUD_CEC_ISET REG(0x0fa4)
|
||||
#define HDMI_RX_AUD_FIFO_IEN_CLR REG(0x0fa8)
|
||||
#define HDMI_RX_AUD_FIFO_IEN_SET REG(0x0fac)
|
||||
#define HDMI_RX_AUD_FIFO_ISTS REG(0x0fb0)
|
||||
#define HDMI_RX_AUD_FIFO_IEN REG(0x0fb4)
|
||||
#define HDMI_RX_AUD_FIFO_ICLR REG(0x0fb8)
|
||||
#define HDMI_RX_AUD_FIFO_ISET REG(0x0fbc)
|
||||
#define HDMI_RX_MD_IEN_CLR REG(0x0fc0)
|
||||
#define HDMI_RX_MD_IEN_SET REG(0x0fc4)
|
||||
#define HDMI_RX_MD_ISTS REG(0x0fc8)
|
||||
#define HDMI_RX_MD_IEN REG(0x0fcc)
|
||||
#define HDMI_RX_MD_ICLR REG(0x0fd0)
|
||||
#define HDMI_RX_MD_ISET REG(0x0fd4)
|
||||
#define HDMI_RX_HDMI_IEN_CLR REG(0x0fd8)
|
||||
#define HDMI_RX_HDMI_IEN_SET REG(0x0fdc)
|
||||
#define HDCP_DKSET_DONE_ENCLR_MASK BIT(31)
|
||||
#define HDCP_DKSET_DONE_ENCLR(x) UPDATE(x, 31, 31)
|
||||
#define HDMI_RX_HDMI_ISTS REG(0x0fe0)
|
||||
#define HDMI_RX_HDMI_IEN REG(0x0fe4)
|
||||
#define HDMI_RX_HDMI_ICLR REG(0x0fe8)
|
||||
#define HDMI_RX_HDMI_ISET REG(0x0fec)
|
||||
#define HDMI_RX_DMI_SW_RST REG(0x0ff0)
|
||||
#define HDMI_RX_DMI_DISABLE_IF REG(0x0ff4)
|
||||
#define MAIN_ENABLE BIT(0)
|
||||
#define MODET_ENABLE BIT(1)
|
||||
#define HDMI_ENABLE BIT(2)
|
||||
#define BUS_ENABLE BIT(3)
|
||||
#define AUD_ENABLE BIT(4)
|
||||
#define CEC_ENABLE BIT(5)
|
||||
#define PIXEL_ENABLE BIT(6)
|
||||
#define VID_ENABLE BIT(7)
|
||||
#define TMDS_ENABLE_MASK BIT(16)
|
||||
#define TMDS_ENABLE(x) UPDATE(x, 16, 16)
|
||||
#define HDMI_RX_DMI_MODULE_ID_EXT REG(0x0ff8)
|
||||
#define HDMI_RX_DMI_MODULE_ID REG(0x0ffc)
|
||||
#define HDMI_RX_CEC_CTRL REG(0x1f00)
|
||||
#define HDMI_RX_CEC_MASK REG(0x1f08)
|
||||
#define HDMI_RX_CEC_ADDR_L REG(0x1f14)
|
||||
#define HDMI_RX_CEC_ADDR_H REG(0x1f18)
|
||||
#define HDMI_RX_CEC_TX_CNT REG(0x1f1c)
|
||||
#define HDMI_RX_CEC_RX_CNT REG(0x1f20)
|
||||
#define HDMI_RX_CEC_TX_DATA_0 REG(0x1f40)
|
||||
#define HDMI_RX_CEC_TX_DATA_1 REG(0x1f44)
|
||||
#define HDMI_RX_CEC_TX_DATA_2 REG(0x1f48)
|
||||
#define HDMI_RX_CEC_TX_DATA_3 REG(0x1f4c)
|
||||
#define HDMI_RX_CEC_TX_DATA_4 REG(0x1f50)
|
||||
#define HDMI_RX_CEC_TX_DATA_5 REG(0x1f54)
|
||||
#define HDMI_RX_CEC_TX_DATA_6 REG(0x1f58)
|
||||
#define HDMI_RX_CEC_TX_DATA_7 REG(0x1f5c)
|
||||
#define HDMI_RX_CEC_TX_DATA_8 REG(0x1f60)
|
||||
#define HDMI_RX_CEC_TX_DATA_9 REG(0x1f64)
|
||||
#define HDMI_RX_CEC_TX_DATA_10 REG(0x1f68)
|
||||
#define HDMI_RX_CEC_TX_DATA_11 REG(0x1f6c)
|
||||
#define HDMI_RX_CEC_TX_DATA_12 REG(0x1f70)
|
||||
#define HDMI_RX_CEC_TX_DATA_13 REG(0x1f74)
|
||||
#define HDMI_RX_CEC_TX_DATA_14 REG(0x1f78)
|
||||
#define HDMI_RX_CEC_TX_DATA_15 REG(0x1f7c)
|
||||
#define HDMI_RX_CEC_RX_DATA_0 REG(0x1f80)
|
||||
#define HDMI_RX_CEC_RX_DATA_1 REG(0x1f84)
|
||||
#define HDMI_RX_CEC_RX_DATA_2 REG(0x1f88)
|
||||
#define HDMI_RX_CEC_RX_DATA_3 REG(0x1f8c)
|
||||
#define HDMI_RX_CEC_RX_DATA_4 REG(0x1f90)
|
||||
#define HDMI_RX_CEC_RX_DATA_5 REG(0x1f94)
|
||||
#define HDMI_RX_CEC_RX_DATA_6 REG(0x1f98)
|
||||
#define HDMI_RX_CEC_RX_DATA_7 REG(0x1f9c)
|
||||
#define HDMI_RX_CEC_RX_DATA_8 REG(0x1fa0)
|
||||
#define HDMI_RX_CEC_RX_DATA_9 REG(0x1fa4)
|
||||
#define HDMI_RX_CEC_RX_DATA_10 REG(0x1fa8)
|
||||
#define HDMI_RX_CEC_RX_DATA_11 REG(0x1fac)
|
||||
#define HDMI_RX_CEC_RX_DATA_12 REG(0x1fb0)
|
||||
#define HDMI_RX_CEC_RX_DATA_13 REG(0x1fb4)
|
||||
#define HDMI_RX_CEC_RX_DATA_14 REG(0x1fb8)
|
||||
#define HDMI_RX_CEC_RX_DATA_15 REG(0x1fbc)
|
||||
#define HDMI_RX_CEC_LOCK REG(0x1fc0)
|
||||
#define HDMI_RX_CEC_WAKEUPCTRL REG(0x1fc4)
|
||||
#define HDMI_RX_CBUSSWRESETREQ REG(0x3000)
|
||||
#define HDMI_RX_CBUSENABLEIF REG(0x3004)
|
||||
#define HDMI_RX_CB_LOCKONCLOCK_STS REG(0x3010)
|
||||
#define HDMI_RX_CB_LOCKONCLOCKCLR REG(0x3014)
|
||||
#define HDMI_RX_CBUSIOCTRL REG(0x3020)
|
||||
#define HDMI_RX_DD_CTRL REG(0x3040)
|
||||
#define HDMI_RX_DD_OP_CTRL REG(0x3044)
|
||||
#define HDMI_RX_DD_STS REG(0x3048)
|
||||
#define HDMI_RX_DD_BYPASS_EN REG(0x304c)
|
||||
#define HDMI_RX_DD_BYPASS_CTRL REG(0x3050)
|
||||
#define HDMI_RX_DD_BYPASS_CBUS REG(0x3054)
|
||||
#define HDMI_RX_LL_TXPCKFIFO REG(0x3080)
|
||||
#define HDMI_RX_LL_RXPCKFIFO_RD_CLR REG(0x3084)
|
||||
#define HDMI_RX_LL_RXPCKFIFO_A REG(0x3088)
|
||||
#define HDMI_RX_LL_RXPCKFIFO_B REG(0x308c)
|
||||
#define HDMI_RX_LL_TXPCKCTRL_0 REG(0x3090)
|
||||
#define HDMI_RX_LL_TXPCKCTRL_1 REG(0x3094)
|
||||
#define HDMI_RX_LL_PCKFIFO_STS REG(0x309c)
|
||||
#define HDMI_RX_LL_RXPCKCTRL_0 REG(0x30a0)
|
||||
#define HDMI_RX_LL_RXPCKCTRL_1 REG(0x30a4)
|
||||
#define HDMI_RX_LL_INTTRSHLDCTRL REG(0x30b0)
|
||||
#define HDMI_RX_LL_INTCNTCTRL REG(0x30b4)
|
||||
#define HDMI_RX_LL_INTCNT_0 REG(0x30b8)
|
||||
#define HDMI_RX_LL_INTCNT_1 REG(0x30bc)
|
||||
#define HDMI_RX_CBHDCP_OPCTRL REG(0x3100)
|
||||
#define HDMI_RX_CBHDCP_WDATA_0 REG(0x3104)
|
||||
#define HDMI_RX_CBHDCP_WDATA_1 REG(0x3108)
|
||||
#define HDMI_RX_CBHDCP_RDATA_0 REG(0x310c)
|
||||
#define HDMI_RX_CBHDCP_RDATA_1 REG(0x3110)
|
||||
#define HDMI_RX_CBHDCP_STATUS REG(0x3114)
|
||||
#define HDMI_RX_CBHDCP_DDC_REPORT REG(0x3118)
|
||||
#define HDMI_RX_ISTAT_CB_DD REG(0x3200)
|
||||
#define HDMI_RX_IMASK_CB_DD REG(0x3204)
|
||||
#define HDMI_RX_IFORCE_CB_DD REG(0x3208)
|
||||
#define HDMI_RX_ICLEAR_CB_DD REG(0x320c)
|
||||
#define HDMI_RX_IMUTE_CB_DD REG(0x3210)
|
||||
#define HDMI_RX_ISTAT_CB_LL REG(0x3220)
|
||||
#define HDMI_RX_IMASK_CB_LL REG(0x3224)
|
||||
#define HDMI_RX_IFORCE_CB_LL REG(0x3228)
|
||||
#define HDMI_RX_ICLEAR_CB_LL REG(0x322c)
|
||||
#define HDMI_RX_IMUTE_CB_LL REG(0x3230)
|
||||
#define HDMI_RX_ISTAT_CB_HDCP REG(0x3240)
|
||||
#define HDMI_RX_IMASK_CB_HDCP REG(0x3244)
|
||||
#define HDMI_RX_IFORCE_CB_HDCP REG(0x3248)
|
||||
#define HDMI_RX_ICLEAR_CB_HDCP REG(0x324c)
|
||||
#define HDMI_RX_IMUTE_CB_HDCP REG(0x3250)
|
||||
#define HDMI_RX_ISTAT_CB_MCTRL REG(0x3260)
|
||||
#define HDMI_RX_IMASK_CB_MCTRL REG(0x3264)
|
||||
#define HDMI_RX_IFORCE_CB_MCTRL REG(0x3268)
|
||||
#define HDMI_RX_ICLEAR_CB_MCTRL REG(0x326c)
|
||||
#define HDMI_RX_IMUTE_CB_MCTRL REG(0x3270)
|
||||
#define HDMI_RX_IMASTER_MUTE_CB REG(0x32e0)
|
||||
#define HDMI_RX_IVECTOR_INDEX_CB REG(0x32e4)
|
||||
#define HDMI_RX_MAX_REGISTER HDMI_RX_IVECTOR_INDEX_CB
|
||||
|
||||
struct rk628_hdmirx {
|
||||
struct drm_bridge base;
|
||||
struct drm_bridge *bridge;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regmap *grf;
|
||||
struct phy *phy;
|
||||
struct clk *pclk;
|
||||
struct clk *cec_clk;
|
||||
struct clk *aud_clk;
|
||||
struct clk *imodet_clk;
|
||||
struct reset_control *hdmirx;
|
||||
struct reset_control *hdmirx_pon;
|
||||
struct rk628 *parent;
|
||||
struct drm_display_mode mode;
|
||||
};
|
||||
|
||||
static const struct regmap_range rk628_hdmirx_readable_ranges[] = {
|
||||
regmap_reg_range(HDMI_RX_HDMI_SETUP_CTRL, HDMI_RX_HDMI_TIMER_CTRL),
|
||||
regmap_reg_range(HDMI_RX_HDMI_MODE_RECOVER, HDMI_RX_HDMI_ERD_STS),
|
||||
regmap_reg_range(HDMI_RX_MD_HCTRL1, HDMI_RX_MD_STS),
|
||||
regmap_reg_range(HDMI_RX_PDEC_ACRM_CTRL, HDMI_RX_PDEC_ASP_ERR),
|
||||
regmap_reg_range(HDMI_RX_PDEC_AVI_HB, HDMI_RX_PDEC_AVI_LRB),
|
||||
regmap_reg_range(HDMI_RX_PDEC_AIF_CTRL, HDMI_RX_PDEC_GMD_PB),
|
||||
regmap_reg_range(HDMI_RX_HDMI20_CONTROL, HDMI_RX_CHLOCK_CONFIG),
|
||||
regmap_reg_range(HDMI_RX_SCDC_REGS1, HDMI_RX_SCDC_REGS3),
|
||||
regmap_reg_range(HDMI_RX_SCDC_WRDATA0, HDMI_RX_SCDC_WRDATA7),
|
||||
regmap_reg_range(HDMI_RX_DMI_DISABLE_IF, HDMI_RX_DMI_DISABLE_IF),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table rk628_hdmirx_readable_table = {
|
||||
.yes_ranges = rk628_hdmirx_readable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(rk628_hdmirx_readable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config rk628_hdmirx_regmap_config = {
|
||||
.name = "hdmirx",
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = HDMI_RX_MAX_REGISTER,
|
||||
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.rd_table = &rk628_hdmirx_readable_table,
|
||||
};
|
||||
|
||||
static inline struct rk628_hdmirx *bridge_to_hdmirx(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct rk628_hdmirx, base);
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_ctrl_enable(struct rk628_hdmirx *hdmirx)
|
||||
{
|
||||
clk_prepare_enable(hdmirx->pclk);
|
||||
clk_prepare_enable(hdmirx->aud_clk);
|
||||
clk_prepare_enable(hdmirx->imodet_clk);
|
||||
|
||||
reset_control_deassert(hdmirx->hdmirx);
|
||||
reset_control_deassert(hdmirx->hdmirx_pon);
|
||||
|
||||
regmap_update_bits(hdmirx->grf, GRF_SYSTEM_CON0,
|
||||
SW_INPUT_MODE_MASK,
|
||||
SW_INPUT_MODE(INPUT_MODE_HDMI));
|
||||
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_DMI_SW_RST, 0x000101ff);
|
||||
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_DMI_DISABLE_IF, 0x00000000);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_DMI_DISABLE_IF, 0x0000017f);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_DMI_DISABLE_IF, 0x0001017f);
|
||||
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_HDMI20_CONTROL, 0x10001f10);
|
||||
|
||||
regmap_update_bits(hdmirx->regmap, HDMI_RX_CHLOCK_CONFIG,
|
||||
CHLOCKMAXER_MASK | MILISECTIMERLIMIT_MASK,
|
||||
CHLOCKMAXER(0x1) | MILISECTIMERLIMIT(49500));
|
||||
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_SCDC_CONFIG, 0x00000001);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_DMI_SW_RST, 0x000001fe);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_HDMI_CKM_EVLTM, 0x0016fff0);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_HDMI_CKM_F, 0xf98a0190);
|
||||
|
||||
regmap_update_bits(hdmirx->regmap, HDMI_RX_HDMI_MODE_RECOVER,
|
||||
SPIKE_FILTER_EN_MASK | DVI_MODE_HYST_MASK |
|
||||
HDMI_MODE_HYST_MASK | HDMI_MODE_MASK |
|
||||
GB_DET_MASK | EESS_OESS_MASK | SEL_CTL01_MASK,
|
||||
SPIKE_FILTER_EN(0) |
|
||||
DVI_MODE_HYST(0) |
|
||||
HDMI_MODE_HYST(0) |
|
||||
HDMI_MODE(3) |
|
||||
GB_DET(2) |
|
||||
EESS_OESS(0) |
|
||||
SEL_CTL01(1));
|
||||
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_PDEC_CTRL, 0xbfff8011);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_PDEC_ASP_CTRL, 0x00000040);
|
||||
|
||||
regmap_update_bits(hdmirx->regmap, HDMI_RX_HDMI_RESMPL_CTRL,
|
||||
MAN_VID_DEREPEAT_MASK, MAN_VID_DEREPEAT(1));
|
||||
|
||||
regmap_update_bits(hdmirx->regmap, HDMI_RX_HDMI_SYNC_CTRL,
|
||||
VS_POL_ADJ_MODE_MASK | HS_POL_ADJ_MODE_MASK,
|
||||
VS_POL_ADJ_MODE(2) | HS_POL_ADJ_MODE(2));
|
||||
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_PDEC_ERR_FILTER, 0x00000008);
|
||||
|
||||
regmap_update_bits(hdmirx->regmap, HDMI_RX_SCDC_I2CCONFIG,
|
||||
I2CSPIKESUPPR_MASK, I2CSPIKESUPPR(1));
|
||||
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_SCDC_CONFIG, 0x00000001);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_SCDC_WRDATA0, 0xabcdef01);
|
||||
|
||||
regmap_update_bits(hdmirx->regmap, HDMI_RX_CHLOCK_CONFIG,
|
||||
CHLOCKMAXER_MASK | MILISECTIMERLIMIT_MASK,
|
||||
CHLOCKMAXER(0x1) | MILISECTIMERLIMIT(49500));
|
||||
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_HDMI_ERROR_PROTECT, 0x000d0c98);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_MD_HCTRL1, 0x00000010);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_MD_HCTRL2, 0x00001738);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_MD_VCTRL, 0x00000012);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_MD_VTH, 0x0000073a);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_MD_IL_POL, 0x00000004);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_PDEC_ACRM_CTRL, 0x00000000);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_HDMI_DCM_CTRL, 0x00040414);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_HDMI_PCB_CTRL, 0x00100000);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_HDMI_SETUP_CTRL, 0x0f000fff);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_HDMI_CKM_EVLTM, 0x00104260);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_HDMI_CKM_F, 0x0f2d0eed);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_DMI_DISABLE_IF, 0x00000001);
|
||||
udelay(400);
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_DMI_DISABLE_IF, 0x0001017f);
|
||||
regmap_update_bits(hdmirx->regmap, HDMI_RX_HDMI_RESMPL_CTRL,
|
||||
MAN_VID_DEREPEAT_MASK, MAN_VID_DEREPEAT(1));
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_DMI_SW_RST, 0x000001fe);
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_ctrl_disable(struct rk628_hdmirx *hdmirx)
|
||||
{
|
||||
reset_control_assert(hdmirx->hdmirx);
|
||||
reset_control_assert(hdmirx->hdmirx_pon);
|
||||
clk_disable_unprepare(hdmirx->pclk);
|
||||
clk_disable_unprepare(hdmirx->aud_clk);
|
||||
clk_disable_unprepare(hdmirx->imodet_clk);
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
bool locked;
|
||||
u32 value, i, hact, vact, bus_width, hdisplay, vdisplay;
|
||||
struct rk628_hdmirx *hdmirx = bridge_to_hdmirx(bridge);
|
||||
|
||||
/* force 594m mode to yuv420 format */
|
||||
if (hdmirx->mode.clock == 594000) {
|
||||
/*
|
||||
* bit30 is used to indicate whether it is
|
||||
* yuv420 format
|
||||
*/
|
||||
bus_width = hdmirx->mode.clock | BIT(30);
|
||||
hdisplay = hdmirx->mode.hdisplay / 2;
|
||||
} else {
|
||||
bus_width = hdmirx->mode.clock;
|
||||
hdisplay = hdmirx->mode.hdisplay;
|
||||
}
|
||||
|
||||
vdisplay = hdmirx->mode.vdisplay;
|
||||
|
||||
phy_set_bus_width(hdmirx->phy, bus_width);
|
||||
phy_power_on(hdmirx->phy);
|
||||
usleep_range(10*1000, 11*1000);
|
||||
rk628_hdmirx_ctrl_enable(hdmirx);
|
||||
|
||||
/* if hdmirx ctrl unlock or get incorrect timing, reset ctrl and phy */
|
||||
for (i = 0; i < 5; i++) {
|
||||
usleep_range(100*1000, 110*1000);
|
||||
regmap_read(hdmirx->regmap, HDMI_RX_SCDC_REGS1, &value);
|
||||
dev_dbg(hdmirx->dev, "HDMI_RX_SCDC_REGS1:0x%x\n", value);
|
||||
value = (value >> 8) & 0xf;
|
||||
|
||||
regmap_read(hdmirx->regmap, HDMI_RX_MD_HACT_PX, &hact);
|
||||
regmap_read(hdmirx->regmap, HDMI_RX_MD_VAL, &vact);
|
||||
|
||||
hact = hact & 0xffff;
|
||||
vact = vact & 0xffff;
|
||||
dev_dbg(hdmirx->dev, "hact:%d,vact:%d\n", hact, vact);
|
||||
|
||||
if (value == 0xf && hact == hdisplay && vact == vdisplay)
|
||||
locked = true;
|
||||
else
|
||||
locked = false;
|
||||
|
||||
if (!locked) {
|
||||
rk628_hdmirx_ctrl_disable(hdmirx);
|
||||
usleep_range(10*1000, 11*1000);
|
||||
phy_power_off(hdmirx->phy);
|
||||
usleep_range(10*1000, 11*1000);
|
||||
phy_power_on(hdmirx->phy);
|
||||
usleep_range(10*1000, 11*1000);
|
||||
rk628_hdmirx_ctrl_enable(hdmirx);
|
||||
} else {
|
||||
/* hdmirx ctrl get correct timing, enable output */
|
||||
regmap_write(hdmirx->regmap, HDMI_RX_DMI_DISABLE_IF,
|
||||
0x000001ff);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(hdmirx->dev, "hdmirx channel can't lock!\n");
|
||||
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_hdmirx *hdmirx = bridge_to_hdmirx(bridge);
|
||||
|
||||
rk628_hdmirx_ctrl_disable(hdmirx);
|
||||
phy_power_off(hdmirx->phy);
|
||||
}
|
||||
|
||||
static int rk628_hdmirx_bridge_attach(struct drm_bridge *bridge,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
{
|
||||
struct rk628_hdmirx *hdmirx = bridge_to_hdmirx(bridge);
|
||||
struct device *dev = hdmirx->dev;
|
||||
int ret;
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1,
|
||||
NULL, &hdmirx->bridge);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to find next bridge\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = drm_bridge_attach(bridge->encoder, hdmirx->bridge, bridge, flags);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to attach bridge\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_bridge_mode_set(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adj)
|
||||
{
|
||||
struct rk628_hdmirx *hdmirx = bridge_to_hdmirx(bridge);
|
||||
|
||||
drm_mode_copy(&hdmirx->mode, adj);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs rk628_hdmirx_bridge_funcs = {
|
||||
.attach = rk628_hdmirx_bridge_attach,
|
||||
.enable = rk628_hdmirx_bridge_enable,
|
||||
.disable = rk628_hdmirx_bridge_disable,
|
||||
.mode_set = rk628_hdmirx_bridge_mode_set,
|
||||
};
|
||||
|
||||
static int rk628_hdmirx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct platform_device_info pdevinfo;
|
||||
struct rk628_hdmirx *hdmirx;
|
||||
int ret, irq;
|
||||
|
||||
if (!of_device_is_available(dev->of_node))
|
||||
return -ENODEV;
|
||||
|
||||
hdmirx = devm_kzalloc(dev, sizeof(*hdmirx), GFP_KERNEL);
|
||||
if (!hdmirx)
|
||||
return -ENOMEM;
|
||||
|
||||
hdmirx->dev = dev;
|
||||
hdmirx->parent = rk628;
|
||||
platform_set_drvdata(pdev, hdmirx);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
hdmirx->grf = rk628->grf;
|
||||
if (!hdmirx->grf)
|
||||
return -ENODEV;
|
||||
|
||||
hdmirx->pclk = devm_clk_get(dev, "pclk");
|
||||
if (IS_ERR(hdmirx->pclk)) {
|
||||
ret = PTR_ERR(hdmirx->pclk);
|
||||
dev_err(dev, "failed to get pclk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdmirx->cec_clk = devm_clk_get(dev, "cec");
|
||||
if (IS_ERR(hdmirx->cec_clk)) {
|
||||
ret = PTR_ERR(hdmirx->cec_clk);
|
||||
dev_err(dev, "failed to get cec clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdmirx->aud_clk = devm_clk_get(dev, "audio");
|
||||
if (IS_ERR(hdmirx->aud_clk)) {
|
||||
ret = PTR_ERR(hdmirx->aud_clk);
|
||||
dev_err(dev, "failed to get audio clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdmirx->imodet_clk = devm_clk_get(dev, "imodet");
|
||||
if (IS_ERR(hdmirx->imodet_clk)) {
|
||||
ret = PTR_ERR(hdmirx->imodet_clk);
|
||||
dev_err(dev, "failed to get imodet clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdmirx->hdmirx = of_reset_control_get(dev->of_node, "hdmirx");
|
||||
if (IS_ERR(hdmirx->hdmirx)) {
|
||||
ret = PTR_ERR(hdmirx->hdmirx);
|
||||
DRM_DEV_ERROR(dev, "failed to get hdmirx control: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdmirx->hdmirx_pon = of_reset_control_get(dev->of_node, "hdmirx_pon");
|
||||
if (IS_ERR(hdmirx->hdmirx_pon)) {
|
||||
ret = PTR_ERR(hdmirx->hdmirx_pon);
|
||||
DRM_DEV_ERROR(dev, "failed to get hdmirx_pon control: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdmirx->phy = devm_of_phy_get(dev, dev->of_node, NULL);
|
||||
if (IS_ERR(hdmirx->phy)) {
|
||||
ret = PTR_ERR(hdmirx->phy);
|
||||
dev_err(dev, "failed to get phy: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdmirx->regmap = devm_regmap_init_i2c(rk628->client,
|
||||
&rk628_hdmirx_regmap_config);
|
||||
if (IS_ERR(hdmirx->regmap)) {
|
||||
ret = PTR_ERR(hdmirx->regmap);
|
||||
dev_err(dev, "failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdmirx->base.funcs = &rk628_hdmirx_bridge_funcs;
|
||||
hdmirx->base.of_node = dev->of_node;
|
||||
drm_bridge_add(&hdmirx->base);
|
||||
|
||||
memset(&pdevinfo, 0, sizeof(pdevinfo));
|
||||
pdevinfo.parent = dev;
|
||||
pdevinfo.id = PLATFORM_DEVID_AUTO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk628_hdmirx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628_hdmirx *hdmirx = platform_get_drvdata(pdev);
|
||||
|
||||
drm_bridge_remove(&hdmirx->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rk628_hdmirx_of_match[] = {
|
||||
{ .compatible = "rockchip,rk628-hdmirx", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk628_hdmirx_of_match);
|
||||
|
||||
static struct platform_driver rk628_hdmirx_driver = {
|
||||
.driver = {
|
||||
.name = "rk628-hdmirx",
|
||||
.of_match_table = of_match_ptr(rk628_hdmirx_of_match),
|
||||
},
|
||||
.probe = rk628_hdmirx_probe,
|
||||
.remove = rk628_hdmirx_remove,
|
||||
};
|
||||
module_platform_driver(rk628_hdmirx_driver);
|
||||
|
||||
MODULE_AUTHOR("Algea Cao <algea.cao@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Rockchip RK628 HDMI RX driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1,320 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/media-bus-format.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/rk628.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include <video/of_display_timing.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
enum lvds_format {
|
||||
LVDS_FORMAT_VESA_24BIT,
|
||||
LVDS_FORMAT_JEIDA_24BIT,
|
||||
LVDS_FORMAT_JEIDA_18BIT,
|
||||
LVDS_FORMAT_VESA_18BIT,
|
||||
};
|
||||
|
||||
enum lvds_link_type {
|
||||
LVDS_SINGLE_LINK,
|
||||
LVDS_DUAL_LINK_ODD_EVEN_PIXELS,
|
||||
LVDS_DUAL_LINK_EVEN_ODD_PIXELS,
|
||||
LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS,
|
||||
LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS,
|
||||
};
|
||||
|
||||
struct rk628_lvds {
|
||||
struct drm_bridge base;
|
||||
struct drm_connector connector;
|
||||
struct drm_panel *panel;
|
||||
struct drm_display_mode mode;
|
||||
struct device *dev;
|
||||
struct regmap *grf;
|
||||
struct phy *phy;
|
||||
struct rk628 *parent;
|
||||
enum lvds_format format;
|
||||
enum lvds_link_type link_type;
|
||||
};
|
||||
|
||||
static inline struct rk628_lvds *bridge_to_lvds(struct drm_bridge *b)
|
||||
{
|
||||
return container_of(b, struct rk628_lvds, base);
|
||||
}
|
||||
|
||||
static inline struct rk628_lvds *connector_to_lvds(struct drm_connector *c)
|
||||
{
|
||||
return container_of(c, struct rk628_lvds, connector);
|
||||
}
|
||||
|
||||
static enum lvds_format rk628_lvds_get_format(u32 bus_format)
|
||||
{
|
||||
switch (bus_format) {
|
||||
case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
|
||||
return LVDS_FORMAT_JEIDA_24BIT;
|
||||
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
|
||||
return LVDS_FORMAT_VESA_18BIT;
|
||||
case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
|
||||
default:
|
||||
return LVDS_FORMAT_VESA_24BIT;
|
||||
}
|
||||
}
|
||||
|
||||
static enum lvds_link_type rk628_lvds_get_link_type(struct rk628_lvds *lvds)
|
||||
{
|
||||
struct device *dev = lvds->dev;
|
||||
const char *str;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_string(dev->of_node, "rockchip,link-type", &str);
|
||||
if (ret < 0)
|
||||
return LVDS_SINGLE_LINK;
|
||||
|
||||
if (!strcmp(str, "dual-link-odd-even-pixels"))
|
||||
return LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
|
||||
else if (!strcmp(str, "dual-link-even-odd-pixels"))
|
||||
return LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
|
||||
else if (!strcmp(str, "dual-link-left-right-pixels"))
|
||||
return LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS;
|
||||
else if (!strcmp(str, "dual-link-right-left-pixels"))
|
||||
return LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS;
|
||||
else
|
||||
return LVDS_SINGLE_LINK;
|
||||
}
|
||||
|
||||
static struct drm_encoder *
|
||||
rk628_lvds_connector_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct rk628_lvds *lvds = connector_to_lvds(connector);
|
||||
|
||||
return lvds->base.encoder;
|
||||
}
|
||||
|
||||
static int rk628_lvds_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct rk628_lvds *lvds = connector_to_lvds(connector);
|
||||
struct drm_display_info *info = &connector->display_info;
|
||||
int num_modes = 0;
|
||||
|
||||
num_modes = drm_panel_get_modes(lvds->panel, connector);
|
||||
|
||||
if (info->num_bus_formats)
|
||||
lvds->format = rk628_lvds_get_format(info->bus_formats[0]);
|
||||
else
|
||||
lvds->format = LVDS_FORMAT_VESA_24BIT;
|
||||
|
||||
return num_modes;
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs
|
||||
rk628_lvds_connector_helper_funcs = {
|
||||
.get_modes = rk628_lvds_connector_get_modes,
|
||||
.best_encoder = rk628_lvds_connector_best_encoder,
|
||||
};
|
||||
|
||||
static void rk628_lvds_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs rk628_lvds_connector_funcs = {
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = rk628_lvds_connector_destroy,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static void rk628_lvds_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_lvds *lvds = bridge_to_lvds(bridge);
|
||||
const struct drm_display_mode *mode = &lvds->mode;
|
||||
u32 val, bus_width;
|
||||
int ret;
|
||||
|
||||
regmap_update_bits(lvds->grf, GRF_SYSTEM_CON0, SW_OUTPUT_MODE_MASK,
|
||||
SW_OUTPUT_MODE(OUTPUT_MODE_LVDS));
|
||||
|
||||
switch (lvds->link_type) {
|
||||
case LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
|
||||
val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(0) |
|
||||
SW_LVDS_CON_DUAL_SEL(0);
|
||||
bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
|
||||
break;
|
||||
case LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
|
||||
val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(1) |
|
||||
SW_LVDS_CON_DUAL_SEL(0);
|
||||
bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
|
||||
break;
|
||||
case LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS:
|
||||
val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(0) |
|
||||
SW_LVDS_CON_DUAL_SEL(1);
|
||||
regmap_update_bits(lvds->grf, GRF_POST_PROC_CON,
|
||||
SW_SPLIT_EN, SW_SPLIT_EN);
|
||||
bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
|
||||
break;
|
||||
case LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS:
|
||||
val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(1) |
|
||||
SW_LVDS_CON_DUAL_SEL(1);
|
||||
regmap_update_bits(lvds->grf, GRF_POST_PROC_CON,
|
||||
SW_SPLIT_EN, SW_SPLIT_EN);
|
||||
bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
|
||||
break;
|
||||
case LVDS_SINGLE_LINK:
|
||||
default:
|
||||
val = SW_LVDS_CON_CHASEL(0) | SW_LVDS_CON_STARTSEL(0) |
|
||||
SW_LVDS_CON_DUAL_SEL(0);
|
||||
bus_width = COMBTXPHY_MODULEA_EN;
|
||||
break;
|
||||
}
|
||||
|
||||
val |= SW_LVDS_CON_SELECT(lvds->format) |
|
||||
SW_LVDS_CON_MSBSEL(0) |
|
||||
SW_LVDS_CON_CLKINV(0);
|
||||
regmap_write(lvds->grf, GRF_LVDS_TX_CON, val);
|
||||
|
||||
bus_width |= (mode->clock / 1000) << 8;
|
||||
phy_set_bus_width(lvds->phy, bus_width);
|
||||
|
||||
ret = phy_set_mode(lvds->phy, PHY_MODE_LVDS);
|
||||
if (ret) {
|
||||
dev_err(lvds->dev, "failed to set phy mode: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
phy_power_on(lvds->phy);
|
||||
|
||||
drm_panel_prepare(lvds->panel);
|
||||
drm_panel_enable(lvds->panel);
|
||||
}
|
||||
|
||||
static void rk628_lvds_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_lvds *lvds = bridge_to_lvds(bridge);
|
||||
|
||||
drm_panel_disable(lvds->panel);
|
||||
drm_panel_unprepare(lvds->panel);
|
||||
phy_power_off(lvds->phy);
|
||||
}
|
||||
|
||||
static int rk628_lvds_bridge_attach(struct drm_bridge *bridge,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
{
|
||||
struct rk628_lvds *lvds = bridge_to_lvds(bridge);
|
||||
struct drm_connector *connector = &lvds->connector;
|
||||
struct drm_device *drm = bridge->dev;
|
||||
int ret;
|
||||
|
||||
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
|
||||
return 0;
|
||||
|
||||
ret = drm_connector_init(drm, connector, &rk628_lvds_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
if (ret) {
|
||||
dev_err(lvds->dev, "Failed to initialize connector with drm\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_connector_helper_add(connector, &rk628_lvds_connector_helper_funcs);
|
||||
drm_connector_attach_encoder(connector, bridge->encoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk628_lvds_bridge_mode_set(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adj)
|
||||
{
|
||||
struct rk628_lvds *lvds = bridge_to_lvds(bridge);
|
||||
|
||||
drm_mode_copy(&lvds->mode, mode);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs rk628_lvds_bridge_funcs = {
|
||||
.attach = rk628_lvds_bridge_attach,
|
||||
.enable = rk628_lvds_bridge_enable,
|
||||
.disable = rk628_lvds_bridge_disable,
|
||||
.mode_set = rk628_lvds_bridge_mode_set,
|
||||
};
|
||||
|
||||
static int rk628_lvds_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rk628_lvds *lvds;
|
||||
int ret;
|
||||
|
||||
if (!of_device_is_available(dev->of_node))
|
||||
return -ENODEV;
|
||||
|
||||
lvds = devm_kzalloc(dev, sizeof(*lvds), GFP_KERNEL);
|
||||
if (!lvds)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1,
|
||||
&lvds->panel, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lvds->dev = dev;
|
||||
lvds->parent = rk628;
|
||||
lvds->grf = rk628->grf;
|
||||
lvds->link_type = rk628_lvds_get_link_type(lvds);
|
||||
platform_set_drvdata(pdev, lvds);
|
||||
|
||||
lvds->phy = devm_of_phy_get(dev, dev->of_node, NULL);
|
||||
if (IS_ERR(lvds->phy)) {
|
||||
ret = PTR_ERR(lvds->phy);
|
||||
dev_err(dev, "failed to get phy: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
lvds->base.funcs = &rk628_lvds_bridge_funcs;
|
||||
lvds->base.of_node = dev->of_node;
|
||||
drm_bridge_add(&lvds->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk628_lvds_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628_lvds *lvds = platform_get_drvdata(pdev);
|
||||
|
||||
drm_bridge_remove(&lvds->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rk628_lvds_of_match[] = {
|
||||
{ .compatible = "rockchip,rk628-lvds", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk628_lvds_of_match);
|
||||
|
||||
static struct platform_driver rk628_lvds_driver = {
|
||||
.driver = {
|
||||
.name = "rk628-lvds",
|
||||
.of_match_table = of_match_ptr(rk628_lvds_of_match),
|
||||
},
|
||||
.probe = rk628_lvds_probe,
|
||||
.remove = rk628_lvds_remove,
|
||||
};
|
||||
module_platform_driver(rk628_lvds_driver);
|
||||
|
||||
MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Rockchip RK628 LVDS driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1,495 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/mfd/rk628.h>
|
||||
#include <video/of_display_timing.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
#include <drm/drm_of.h>
|
||||
|
||||
enum rk628_mode_sync_pol {
|
||||
MODE_FLAG_NSYNC,
|
||||
MODE_FLAG_PSYNC,
|
||||
};
|
||||
|
||||
struct rk628_post_process {
|
||||
struct drm_bridge base;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_display_mode src_mode;
|
||||
struct drm_display_mode dst_mode;
|
||||
struct device *dev;
|
||||
struct regmap *grf;
|
||||
struct clk *sclk_vop;
|
||||
struct clk *clk_rx_read;
|
||||
struct reset_control *rstc_decoder;
|
||||
struct reset_control *rstc_clk_rx;
|
||||
struct reset_control *rstc_vop;
|
||||
struct rk628 *parent;
|
||||
int sync_pol;
|
||||
};
|
||||
|
||||
static inline struct rk628_post_process *bridge_to_pp(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct rk628_post_process, base);
|
||||
}
|
||||
|
||||
static void calc_dsp_frm_hst_vst(const struct videomode *src,
|
||||
const struct videomode *dst,
|
||||
u32 *dsp_frame_hst, u32 *dsp_frame_vst)
|
||||
{
|
||||
u32 bp_in, bp_out;
|
||||
u32 v_scale_ratio;
|
||||
u64 t_frm_st;
|
||||
u64 t_bp_in, t_bp_out, t_delta, tin;
|
||||
u32 src_pixclock, dst_pixclock;
|
||||
u32 dsp_htotal, src_htotal, src_vtotal;
|
||||
|
||||
src_pixclock = div_u64(1000000000000llu, src->pixelclock);
|
||||
dst_pixclock = div_u64(1000000000000llu, dst->pixelclock);
|
||||
|
||||
src_htotal = src->hsync_len + src->hback_porch + src->hactive +
|
||||
src->hfront_porch;
|
||||
src_vtotal = src->vsync_len + src->vback_porch + src->vactive +
|
||||
src->vfront_porch;
|
||||
dsp_htotal = dst->hsync_len + dst->hback_porch + dst->hactive +
|
||||
dst->hfront_porch;
|
||||
|
||||
bp_in = (src->vback_porch + src->vsync_len) * src_htotal +
|
||||
src->hsync_len + src->hback_porch;
|
||||
bp_out = (dst->vback_porch + dst->vsync_len) * dsp_htotal +
|
||||
dst->hsync_len + dst->hback_porch;
|
||||
|
||||
t_bp_in = bp_in * src_pixclock;
|
||||
t_bp_out = bp_out * dst_pixclock;
|
||||
tin = src_vtotal * src_htotal * src_pixclock;
|
||||
|
||||
v_scale_ratio = src->vactive / dst->vactive;
|
||||
if (v_scale_ratio <= 2)
|
||||
t_delta = 5 * src_htotal * src_pixclock;
|
||||
else
|
||||
t_delta = 12 * src_htotal * src_pixclock;
|
||||
|
||||
if (t_bp_in + t_delta > t_bp_out)
|
||||
t_frm_st = (t_bp_in + t_delta - t_bp_out);
|
||||
else
|
||||
t_frm_st = tin - (t_bp_out - (t_bp_in + t_delta));
|
||||
|
||||
do_div(t_frm_st, src_pixclock);
|
||||
*dsp_frame_hst = do_div(t_frm_st, src_htotal);
|
||||
*dsp_frame_vst = t_frm_st;
|
||||
}
|
||||
|
||||
static void rk628_post_process_scaler_init(struct rk628_post_process *pp,
|
||||
const struct drm_display_mode *s,
|
||||
const struct drm_display_mode *d)
|
||||
{
|
||||
struct videomode src, dst;
|
||||
u32 dsp_frame_hst, dsp_frame_vst;
|
||||
u32 scl_hor_mode, scl_ver_mode;
|
||||
u32 scl_v_factor, scl_h_factor;
|
||||
u32 dsp_htotal, dsp_hs_end, dsp_hact_st, dsp_hact_end;
|
||||
u32 dsp_vtotal, dsp_vs_end, dsp_vact_st, dsp_vact_end;
|
||||
u32 dsp_hbor_end, dsp_hbor_st, dsp_vbor_end, dsp_vbor_st;
|
||||
u16 bor_right = 0, bor_left = 0, bor_up = 0, bor_down = 0;
|
||||
u8 hor_down_mode = 0, ver_down_mode = 0;
|
||||
|
||||
drm_display_mode_to_videomode(s, &src);
|
||||
drm_display_mode_to_videomode(d, &dst);
|
||||
|
||||
dsp_htotal = dst.hsync_len + dst.hback_porch + dst.hactive +
|
||||
dst.hfront_porch;
|
||||
dsp_vtotal = dst.vsync_len + dst.vback_porch + dst.vactive +
|
||||
dst.vfront_porch;
|
||||
dsp_hs_end = dst.hsync_len;
|
||||
dsp_vs_end = dst.vsync_len;
|
||||
dsp_hbor_end = dst.hsync_len + dst.hback_porch + dst.hactive;
|
||||
dsp_hbor_st = dst.hsync_len + dst.hback_porch;
|
||||
dsp_vbor_end = dst.vsync_len + dst.vback_porch + dst.vactive;
|
||||
dsp_vbor_st = dst.vsync_len + dst.vback_porch;
|
||||
dsp_hact_st = dsp_hbor_st + bor_left;
|
||||
dsp_hact_end = dsp_hbor_end - bor_right;
|
||||
dsp_vact_st = dsp_vbor_st + bor_up;
|
||||
dsp_vact_end = dsp_vbor_end - bor_down;
|
||||
|
||||
calc_dsp_frm_hst_vst(&src, &dst, &dsp_frame_hst, &dsp_frame_vst);
|
||||
dev_dbg(pp->dev, "dsp_frame_vst=%d, dsp_frame_hst=%d\n",
|
||||
dsp_frame_vst, dsp_frame_hst);
|
||||
|
||||
if (src.hactive > dst.hactive) {
|
||||
scl_hor_mode = 2;
|
||||
|
||||
if (hor_down_mode == 0) {
|
||||
if ((src.hactive - 1) / (dst.hactive - 1) > 2)
|
||||
scl_h_factor = ((src.hactive - 1) << 14) /
|
||||
(dst.hactive - 1);
|
||||
else
|
||||
scl_h_factor = ((src.hactive - 2) << 14) /
|
||||
(dst.hactive - 1);
|
||||
} else {
|
||||
scl_h_factor = (dst.hactive << 16) /
|
||||
(src.hactive - 1);
|
||||
}
|
||||
|
||||
dev_dbg(pp->dev, "horizontal scale down\n");
|
||||
} else if (src.hactive == dst.hactive) {
|
||||
scl_hor_mode = 0;
|
||||
scl_h_factor = 0;
|
||||
|
||||
dev_dbg(pp->dev, "horizontal no scale\n");
|
||||
} else {
|
||||
scl_hor_mode = 1;
|
||||
scl_h_factor = ((src.hactive - 1) << 16) / (dst.hactive - 1);
|
||||
|
||||
dev_dbg(pp->dev, "horizontal scale up\n");
|
||||
}
|
||||
|
||||
if (src.vactive > dst.vactive) {
|
||||
scl_ver_mode = 2;
|
||||
|
||||
if (ver_down_mode == 0) {
|
||||
if ((src.vactive - 1) / (dst.vactive - 1) > 2)
|
||||
scl_v_factor = ((src.vactive - 1) << 14) /
|
||||
(dst.vactive - 1);
|
||||
else
|
||||
scl_v_factor = ((src.vactive - 2) << 14) /
|
||||
(dst.vactive - 1);
|
||||
} else {
|
||||
scl_v_factor = (dst.vactive << 16) /
|
||||
(src.vactive - 1);
|
||||
}
|
||||
|
||||
dev_dbg(pp->dev, "vertical scale down\n");
|
||||
} else if (src.vactive == dst.vactive) {
|
||||
scl_ver_mode = 0;
|
||||
scl_v_factor = 0;
|
||||
|
||||
dev_dbg(pp->dev, "vertical no scale\n");
|
||||
} else {
|
||||
scl_ver_mode = 1;
|
||||
scl_v_factor = ((src.vactive - 1) << 16) / (dst.vactive - 1);
|
||||
|
||||
dev_dbg(pp->dev, "vertical scale up\n");
|
||||
}
|
||||
|
||||
regmap_update_bits(pp->grf, GRF_RGB_DEC_CON0,
|
||||
SW_HRES_MASK, SW_HRES(src.hactive));
|
||||
regmap_write(pp->grf, GRF_SCALER_CON0,
|
||||
SCL_VER_DOWN_MODE(ver_down_mode) |
|
||||
SCL_HOR_DOWN_MODE(hor_down_mode) |
|
||||
SCL_VER_MODE(scl_ver_mode) | SCL_HOR_MODE(scl_hor_mode));
|
||||
regmap_write(pp->grf, GRF_SCALER_CON1,
|
||||
SCL_V_FACTOR(scl_v_factor) | SCL_H_FACTOR(scl_h_factor));
|
||||
regmap_write(pp->grf, GRF_SCALER_CON2,
|
||||
DSP_FRAME_VST(dsp_frame_vst) |
|
||||
DSP_FRAME_HST(dsp_frame_hst));
|
||||
regmap_write(pp->grf, GRF_SCALER_CON3,
|
||||
DSP_HS_END(dsp_hs_end) | DSP_HTOTAL(dsp_htotal));
|
||||
regmap_write(pp->grf, GRF_SCALER_CON4,
|
||||
DSP_HACT_END(dsp_hact_end) | DSP_HACT_ST(dsp_hact_st));
|
||||
regmap_write(pp->grf, GRF_SCALER_CON5,
|
||||
DSP_VS_END(dsp_vs_end) | DSP_VTOTAL(dsp_vtotal));
|
||||
regmap_write(pp->grf, GRF_SCALER_CON6,
|
||||
DSP_VACT_END(dsp_vact_end) | DSP_VACT_ST(dsp_vact_st));
|
||||
regmap_write(pp->grf, GRF_SCALER_CON7,
|
||||
DSP_HBOR_END(dsp_hbor_end) | DSP_HBOR_ST(dsp_hbor_st));
|
||||
regmap_write(pp->grf, GRF_SCALER_CON8,
|
||||
DSP_VBOR_END(dsp_vbor_end) | DSP_VBOR_ST(dsp_vbor_st));
|
||||
}
|
||||
|
||||
static void rk628_post_process_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_post_process *pp = bridge_to_pp(bridge);
|
||||
struct drm_display_mode *src = &pp->src_mode;
|
||||
struct drm_display_mode *dst = &pp->dst_mode;
|
||||
u64 dst_rate, src_rate;
|
||||
|
||||
reset_control_assert(pp->rstc_decoder);
|
||||
udelay(10);
|
||||
reset_control_deassert(pp->rstc_decoder);
|
||||
udelay(10);
|
||||
|
||||
clk_set_rate(pp->clk_rx_read, src->clock * 1000);
|
||||
clk_prepare_enable(pp->clk_rx_read);
|
||||
reset_control_assert(pp->rstc_clk_rx);
|
||||
udelay(10);
|
||||
reset_control_deassert(pp->rstc_clk_rx);
|
||||
udelay(10);
|
||||
|
||||
src_rate = src->clock * 1000;
|
||||
dst_rate = src_rate * dst->vdisplay * dst->htotal;
|
||||
do_div(dst_rate, src->vdisplay * src->htotal);
|
||||
do_div(dst_rate, 1000);
|
||||
dst->clock = dst_rate;
|
||||
|
||||
clk_set_rate(pp->sclk_vop, dst->clock * 1000);
|
||||
clk_prepare_enable(pp->sclk_vop);
|
||||
reset_control_assert(pp->rstc_vop);
|
||||
udelay(10);
|
||||
reset_control_deassert(pp->rstc_vop);
|
||||
udelay(10);
|
||||
|
||||
regmap_update_bits(pp->grf, GRF_SYSTEM_CON0, SW_VSYNC_POL_MASK,
|
||||
SW_VSYNC_POL(pp->sync_pol));
|
||||
regmap_update_bits(pp->grf, GRF_SYSTEM_CON0, SW_HSYNC_POL_MASK,
|
||||
SW_HSYNC_POL(pp->sync_pol));
|
||||
|
||||
rk628_post_process_scaler_init(pp, src, dst);
|
||||
}
|
||||
|
||||
static void rk628_post_process_bridge_post_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void rk628_post_process_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_post_process *pp = bridge_to_pp(bridge);
|
||||
|
||||
regmap_write(pp->grf, GRF_SCALER_CON0, SCL_EN(1));
|
||||
}
|
||||
|
||||
static void rk628_post_process_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_post_process *pp = bridge_to_pp(bridge);
|
||||
|
||||
regmap_write(pp->grf, GRF_SCALER_CON0, SCL_EN(0));
|
||||
|
||||
clk_disable_unprepare(pp->sclk_vop);
|
||||
clk_disable_unprepare(pp->clk_rx_read);
|
||||
}
|
||||
|
||||
static void rk628_post_process_bridge_mode_set(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adj)
|
||||
{
|
||||
struct rk628_post_process *pp = bridge_to_pp(bridge);
|
||||
struct rk628 *rk628 = pp->parent;
|
||||
|
||||
drm_mode_copy(&pp->src_mode, adj);
|
||||
|
||||
if (rk628->dst_mode_valid)
|
||||
drm_mode_copy(&pp->dst_mode, &rk628->dst_mode);
|
||||
else
|
||||
drm_mode_copy(&pp->dst_mode, &pp->src_mode);
|
||||
|
||||
/* hdmirx 4k-60Hz mode only support yuv420 */
|
||||
if (pp->src_mode.clock == 594000)
|
||||
regmap_write(pp->grf, GRF_CSC_CTRL_CON, SW_Y2R_EN(1));
|
||||
}
|
||||
|
||||
static int rk628_post_process_bridge_attach(struct drm_bridge *bridge,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
{
|
||||
struct rk628_post_process *pp = bridge_to_pp(bridge);
|
||||
struct device *dev = pp->dev;
|
||||
int ret;
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1,
|
||||
NULL, &pp->bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_bridge_attach(bridge->encoder, pp->bridge, bridge, flags);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to attach bridge\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
rk628_post_process_bridge_mode_fixup(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj)
|
||||
{
|
||||
struct rk628_post_process *pp = bridge_to_pp(bridge);
|
||||
|
||||
if (pp->sync_pol == MODE_FLAG_NSYNC) {
|
||||
adj->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
|
||||
adj->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
|
||||
} else {
|
||||
adj->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
|
||||
adj->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs rk628_post_process_bridge_funcs = {
|
||||
.pre_enable = rk628_post_process_bridge_pre_enable,
|
||||
.post_disable = rk628_post_process_bridge_post_disable,
|
||||
.enable = rk628_post_process_bridge_enable,
|
||||
.disable = rk628_post_process_bridge_disable,
|
||||
.mode_set = rk628_post_process_bridge_mode_set,
|
||||
.mode_fixup = rk628_post_process_bridge_mode_fixup,
|
||||
.attach = rk628_post_process_bridge_attach,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* rk628_scaler_add_src_mode - add source mode for scaler
|
||||
* @rk628: parent device
|
||||
* @connector: DRM connector
|
||||
* If need scale, call the function at last of get_modes.
|
||||
*/
|
||||
int rk628_scaler_add_src_mode(struct rk628 *rk628,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct drm_display_mode *pmode;
|
||||
struct drm_display_mode *dst;
|
||||
|
||||
if (!rk628 || !connector)
|
||||
return 0;
|
||||
|
||||
if (drm_mode_validate_driver(connector->dev, &rk628->src_mode) !=
|
||||
MODE_OK)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(pmode, &connector->probed_modes, head) {
|
||||
if (pmode->type & DRM_MODE_TYPE_PREFERRED) {
|
||||
drm_mode_copy(&rk628->dst_mode, pmode);
|
||||
drm_mode_copy(pmode, &rk628->src_mode);
|
||||
pmode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
rk628->dst_mode_valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rk628->dst_mode_valid) {
|
||||
dst = drm_mode_duplicate(connector->dev, &rk628->dst_mode);
|
||||
dst->type &= ~DRM_MODE_TYPE_PREFERRED;
|
||||
drm_mode_probed_add(connector, dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rk628_scaler_add_src_mode);
|
||||
|
||||
/**
|
||||
* rk628_mode_copy - rk628 mode copy
|
||||
* @rk628: parent device
|
||||
* @dst: dst mode
|
||||
* @src: src mode
|
||||
* Call the function at mode_set, replace drm_mode_copy.
|
||||
*/
|
||||
void rk628_mode_copy(struct rk628 *rk628, struct drm_display_mode *dst,
|
||||
const struct drm_display_mode *src)
|
||||
{
|
||||
if (rk628->dst_mode_valid)
|
||||
drm_mode_copy(dst, &rk628->dst_mode);
|
||||
else
|
||||
drm_mode_copy(dst, src);
|
||||
}
|
||||
EXPORT_SYMBOL(rk628_mode_copy);
|
||||
|
||||
static int rk628_post_process_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rk628_post_process *pp;
|
||||
u32 bus_flags;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (!of_device_is_available(dev->of_node))
|
||||
return -ENODEV;
|
||||
|
||||
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
|
||||
if (!pp)
|
||||
return -ENOMEM;
|
||||
|
||||
pp->dev = dev;
|
||||
pp->grf = rk628->grf;
|
||||
platform_set_drvdata(pdev, pp);
|
||||
pp->parent = rk628;
|
||||
|
||||
pp->sclk_vop = devm_clk_get(dev, "sclk_vop");
|
||||
if (IS_ERR(pp->sclk_vop)) {
|
||||
ret = PTR_ERR(pp->sclk_vop);
|
||||
dev_err(dev, "failed to get sclk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pp->clk_rx_read = devm_clk_get(dev, "rx_read");
|
||||
if (IS_ERR(pp->clk_rx_read)) {
|
||||
ret = PTR_ERR(pp->clk_rx_read);
|
||||
dev_err(dev, "failed to get clk_rx_read: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pp->rstc_decoder = of_reset_control_get(dev->of_node, "decoder");
|
||||
if (IS_ERR(pp->rstc_decoder)) {
|
||||
ret = PTR_ERR(pp->rstc_decoder);
|
||||
dev_err(dev, "failed to get decoder reset: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pp->rstc_clk_rx = of_reset_control_get(dev->of_node, "clk_rx");
|
||||
if (IS_ERR(pp->rstc_clk_rx)) {
|
||||
ret = PTR_ERR(pp->rstc_clk_rx);
|
||||
dev_err(dev, "failed to get clk_rx reset: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pp->rstc_vop = of_reset_control_get(dev->of_node, "vop");
|
||||
if (IS_ERR(pp->rstc_vop)) {
|
||||
ret = PTR_ERR(pp->rstc_vop);
|
||||
dev_err(dev, "failed to get vop reset: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "mode-sync-pol", &val);
|
||||
if (ret < 0)
|
||||
pp->sync_pol = MODE_FLAG_PSYNC;
|
||||
else
|
||||
pp->sync_pol = (!val ? MODE_FLAG_NSYNC : MODE_FLAG_PSYNC);
|
||||
|
||||
pp->base.funcs = &rk628_post_process_bridge_funcs;
|
||||
pp->base.of_node = dev->of_node;
|
||||
drm_bridge_add(&pp->base);
|
||||
|
||||
of_get_drm_display_mode(dev->of_node, &rk628->src_mode, &bus_flags,
|
||||
OF_USE_NATIVE_MODE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk628_post_process_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628_post_process *pp = platform_get_drvdata(pdev);
|
||||
|
||||
drm_bridge_remove(&pp->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rk628_post_process_of_match[] = {
|
||||
{ .compatible = "rockchip,rk628-post-process", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk628_post_process_of_match);
|
||||
|
||||
static struct platform_driver rk628_post_process_driver = {
|
||||
.driver = {
|
||||
.name = "rk628-post-process",
|
||||
.of_match_table = of_match_ptr(rk628_post_process_of_match),
|
||||
},
|
||||
.probe = rk628_post_process_probe,
|
||||
.remove = rk628_post_process_remove,
|
||||
};
|
||||
module_platform_driver(rk628_post_process_driver);
|
||||
|
||||
MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Rockchip RK628 Post Process driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1,378 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/rk628.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include <video/of_display_timing.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
enum interface_type {
|
||||
RGB_TX,
|
||||
YUV_RX,
|
||||
YUV_TX,
|
||||
BT1120_RX,
|
||||
BT1120_TX,
|
||||
};
|
||||
|
||||
struct rk628_rgb {
|
||||
struct drm_bridge base;
|
||||
struct drm_connector connector;
|
||||
struct drm_display_mode mode;
|
||||
struct drm_panel *panel;
|
||||
struct drm_bridge *bridge;
|
||||
struct device *dev;
|
||||
struct regmap *grf;
|
||||
struct rk628 *parent;
|
||||
struct clk *decclk;
|
||||
struct reset_control *rstc;
|
||||
bool dual_edge;
|
||||
enum interface_type interface_type;
|
||||
};
|
||||
|
||||
static inline struct rk628_rgb *bridge_to_rgb(struct drm_bridge *b)
|
||||
{
|
||||
return container_of(b, struct rk628_rgb, base);
|
||||
}
|
||||
|
||||
static inline struct rk628_rgb *connector_to_rgb(struct drm_connector *c)
|
||||
{
|
||||
return container_of(c, struct rk628_rgb, connector);
|
||||
}
|
||||
|
||||
static enum interface_type rk628_rgb_get_interface_type(struct rk628_rgb *rgb)
|
||||
{
|
||||
const struct device_node *of_node = rgb->dev->of_node;
|
||||
|
||||
if (of_device_is_compatible(of_node, "rockchip,rk628-yuv-rx"))
|
||||
return YUV_RX;
|
||||
else if (of_device_is_compatible(of_node, "rockchip,rk628-yuv-tx"))
|
||||
return YUV_TX;
|
||||
else if (of_device_is_compatible(of_node, "rockchip,rk628-bt1120-rx"))
|
||||
return BT1120_RX;
|
||||
else if (of_device_is_compatible(of_node, "rockchip,rk628-bt1120-tx"))
|
||||
return BT1120_TX;
|
||||
else
|
||||
return RGB_TX;
|
||||
}
|
||||
|
||||
static struct drm_encoder *
|
||||
rk628_rgb_connector_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct rk628_rgb *rgb = connector_to_rgb(connector);
|
||||
|
||||
return rgb->base.encoder;
|
||||
}
|
||||
|
||||
static int rk628_rgb_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct rk628_rgb *rgb = connector_to_rgb(connector);
|
||||
|
||||
return drm_panel_get_modes(rgb->panel, connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs
|
||||
rk628_rgb_connector_helper_funcs = {
|
||||
.get_modes = rk628_rgb_connector_get_modes,
|
||||
.best_encoder = rk628_rgb_connector_best_encoder,
|
||||
};
|
||||
|
||||
static void rk628_rgb_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs rk628_rgb_connector_funcs = {
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = rk628_rgb_connector_destroy,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static void rk628_bt1120_rx_enable(struct rk628_rgb *rgb)
|
||||
{
|
||||
const struct drm_display_mode *mode = &rgb->mode;
|
||||
|
||||
reset_control_assert(rgb->rstc);
|
||||
udelay(10);
|
||||
reset_control_deassert(rgb->rstc);
|
||||
udelay(10);
|
||||
|
||||
clk_set_rate(rgb->decclk, mode->clock * 1000);
|
||||
clk_prepare_enable(rgb->decclk);
|
||||
|
||||
if (rgb->dual_edge) {
|
||||
regmap_update_bits(rgb->grf, GRF_RGB_DEC_CON0,
|
||||
DEC_DUALEDGE_EN, DEC_DUALEDGE_EN);
|
||||
|
||||
regmap_write(rgb->grf,
|
||||
GRF_BT1120_DCLK_DELAY_CON0, 0x10000000);
|
||||
regmap_write(rgb->grf, GRF_BT1120_DCLK_DELAY_CON1, 0);
|
||||
} else
|
||||
regmap_update_bits(rgb->grf, GRF_RGB_DEC_CON0,
|
||||
DEC_DUALEDGE_EN, 0);
|
||||
|
||||
regmap_update_bits(rgb->grf, GRF_RGB_DEC_CON1,
|
||||
SW_SET_X_MASK, SW_SET_X(mode->hdisplay));
|
||||
regmap_update_bits(rgb->grf, GRF_RGB_DEC_CON2,
|
||||
SW_SET_Y_MASK, SW_SET_Y(mode->vdisplay));
|
||||
|
||||
regmap_update_bits(rgb->grf, GRF_SYSTEM_CON0,
|
||||
SW_BT_DATA_OEN_MASK | SW_INPUT_MODE_MASK,
|
||||
SW_BT_DATA_OEN | SW_INPUT_MODE(INPUT_MODE_BT1120));
|
||||
|
||||
regmap_write(rgb->grf, GRF_CSC_CTRL_CON, SW_Y2R_EN(1));
|
||||
|
||||
regmap_update_bits(rgb->grf, GRF_RGB_DEC_CON0,
|
||||
SW_CAP_EN_PSYNC | SW_CAP_EN_ASYNC | SW_PROGRESS_EN,
|
||||
SW_CAP_EN_PSYNC | SW_CAP_EN_ASYNC | SW_PROGRESS_EN);
|
||||
}
|
||||
|
||||
static void rk628_bt1120_tx_enable(struct rk628_rgb *rgb)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
regmap_update_bits(rgb->grf, GRF_SYSTEM_CON0,
|
||||
SW_BT_DATA_OEN_MASK | SW_OUTPUT_MODE_MASK,
|
||||
SW_OUTPUT_MODE(OUTPUT_MODE_BT1120));
|
||||
regmap_write(rgb->grf, GRF_CSC_CTRL_CON, SW_R2Y_EN(1));
|
||||
regmap_update_bits(rgb->grf, GRF_POST_PROC_CON,
|
||||
SW_DCLK_OUT_INV_EN, SW_DCLK_OUT_INV_EN);
|
||||
|
||||
if (rgb->dual_edge) {
|
||||
val |= ENC_DUALEDGE_EN(1);
|
||||
regmap_write(rgb->grf, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000);
|
||||
regmap_write(rgb->grf, GRF_BT1120_DCLK_DELAY_CON1, 0);
|
||||
}
|
||||
|
||||
val |= BT1120_UV_SWAP(1);
|
||||
regmap_write(rgb->grf, GRF_RGB_ENC_CON, val);
|
||||
|
||||
}
|
||||
|
||||
static void rk628_rgb_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_rgb *rgb = bridge_to_rgb(bridge);
|
||||
|
||||
switch (rgb->interface_type) {
|
||||
case YUV_RX:
|
||||
regmap_write(rgb->grf, GRF_CSC_CTRL_CON, SW_Y2R_EN(1));
|
||||
regmap_update_bits(rgb->grf, GRF_SYSTEM_CON0,
|
||||
SW_BT_DATA_OEN_MASK | SW_INPUT_MODE_MASK,
|
||||
SW_BT_DATA_OEN | SW_INPUT_MODE(INPUT_MODE_YUV));
|
||||
break;
|
||||
case YUV_TX:
|
||||
regmap_write(rgb->grf, GRF_CSC_CTRL_CON, SW_R2Y_EN(1));
|
||||
regmap_update_bits(rgb->grf, GRF_POST_PROC_CON,
|
||||
SW_DCLK_OUT_INV_EN, SW_DCLK_OUT_INV_EN);
|
||||
|
||||
regmap_update_bits(rgb->grf, GRF_SYSTEM_CON0,
|
||||
SW_BT_DATA_OEN_MASK | SW_OUTPUT_MODE_MASK,
|
||||
SW_OUTPUT_MODE(OUTPUT_MODE_YUV));
|
||||
break;
|
||||
case BT1120_RX:
|
||||
rk628_bt1120_rx_enable(rgb);
|
||||
break;
|
||||
case BT1120_TX:
|
||||
rk628_bt1120_tx_enable(rgb);
|
||||
break;
|
||||
case RGB_TX:
|
||||
default:
|
||||
regmap_update_bits(rgb->grf, GRF_SYSTEM_CON0,
|
||||
SW_BT_DATA_OEN_MASK | SW_OUTPUT_MODE_MASK,
|
||||
SW_OUTPUT_MODE(OUTPUT_MODE_RGB));
|
||||
regmap_update_bits(rgb->grf, GRF_POST_PROC_CON,
|
||||
SW_DCLK_OUT_INV_EN, SW_DCLK_OUT_INV_EN);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rgb->panel) {
|
||||
drm_panel_prepare(rgb->panel);
|
||||
drm_panel_enable(rgb->panel);
|
||||
}
|
||||
}
|
||||
|
||||
static void rk628_rgb_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk628_rgb *rgb = bridge_to_rgb(bridge);
|
||||
|
||||
if (rgb->panel) {
|
||||
drm_panel_disable(rgb->panel);
|
||||
drm_panel_unprepare(rgb->panel);
|
||||
}
|
||||
|
||||
if (rgb->decclk)
|
||||
clk_disable_unprepare(rgb->decclk);
|
||||
|
||||
if (rgb->rstc)
|
||||
reset_control_assert(rgb->rstc);
|
||||
}
|
||||
|
||||
static int rk628_rgb_bridge_attach(struct drm_bridge *bridge,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
{
|
||||
struct rk628_rgb *rgb = bridge_to_rgb(bridge);
|
||||
struct drm_connector *connector = &rgb->connector;
|
||||
struct drm_device *drm = bridge->dev;
|
||||
struct device *dev = rgb->dev;
|
||||
int ret;
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1,
|
||||
&rgb->panel, &rgb->bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rgb->interface_type == YUV_RX || rgb->interface_type == BT1120_RX) {
|
||||
if (!rgb->bridge) {
|
||||
dev_err(dev, "decoder failed to find bridge\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ret = drm_bridge_attach(bridge->encoder, rgb->bridge, bridge,
|
||||
flags);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to attach bridge\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
if (rgb->bridge) {
|
||||
ret = drm_bridge_attach(bridge->encoder, rgb->bridge,
|
||||
bridge, flags);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to attach bridge\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
|
||||
return 0;
|
||||
|
||||
if (rgb->panel) {
|
||||
ret = drm_connector_init(drm, connector,
|
||||
&rk628_rgb_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_DPI);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to initialize connector with drm\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_connector_helper_add(connector,
|
||||
&rk628_rgb_connector_helper_funcs);
|
||||
drm_connector_attach_encoder(connector,
|
||||
bridge->encoder);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk628_rgb_bridge_mode_set(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adj)
|
||||
{
|
||||
struct rk628_rgb *rgb = bridge_to_rgb(bridge);
|
||||
|
||||
drm_mode_copy(&rgb->mode, adj);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs rk628_rgb_bridge_funcs = {
|
||||
.attach = rk628_rgb_bridge_attach,
|
||||
.enable = rk628_rgb_bridge_enable,
|
||||
.disable = rk628_rgb_bridge_disable,
|
||||
.mode_set = rk628_rgb_bridge_mode_set,
|
||||
};
|
||||
|
||||
static int rk628_rgb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rk628_rgb *rgb;
|
||||
int ret;
|
||||
|
||||
if (!of_device_is_available(dev->of_node))
|
||||
return -ENODEV;
|
||||
|
||||
rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL);
|
||||
if (!rgb)
|
||||
return -ENOMEM;
|
||||
|
||||
rgb->dev = dev;
|
||||
rgb->parent = rk628;
|
||||
rgb->grf = rk628->grf;
|
||||
rgb->interface_type = rk628_rgb_get_interface_type(rgb);
|
||||
rgb->dual_edge = of_property_read_bool(dev->of_node, "dual-edge");
|
||||
platform_set_drvdata(pdev, rgb);
|
||||
|
||||
if (rgb->interface_type == BT1120_RX) {
|
||||
rgb->decclk = devm_clk_get(dev, "bt1120dec");
|
||||
if (IS_ERR(rgb->decclk)) {
|
||||
ret = PTR_ERR(rgb->decclk);
|
||||
dev_err(dev, "failed to get dec clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rgb->rstc = of_reset_control_get(dev->of_node, NULL);
|
||||
if (IS_ERR(rgb->rstc)) {
|
||||
ret = PTR_ERR(rgb->rstc);
|
||||
dev_err(dev, "failed to get reset control: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
rgb->base.funcs = &rk628_rgb_bridge_funcs;
|
||||
rgb->base.of_node = dev->of_node;
|
||||
drm_bridge_add(&rgb->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk628_rgb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk628_rgb *rgb = platform_get_drvdata(pdev);
|
||||
|
||||
drm_bridge_remove(&rgb->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rk628_rgb_of_match[] = {
|
||||
{ .compatible = "rockchip,rk628-rgb-tx", },
|
||||
{ .compatible = "rockchip,rk628-yuv-rx", },
|
||||
{ .compatible = "rockchip,rk628-yuv-tx", },
|
||||
{ .compatible = "rockchip,rk628-bt1120-rx", },
|
||||
{ .compatible = "rockchip,rk628-bt1120-tx", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk628_rgb_of_match);
|
||||
|
||||
static struct platform_driver rk628_rgb_driver = {
|
||||
.driver = {
|
||||
.name = "rk628-rgb",
|
||||
.of_match_table = of_match_ptr(rk628_rgb_of_match),
|
||||
},
|
||||
.probe = rk628_rgb_probe,
|
||||
.remove = rk628_rgb_remove,
|
||||
};
|
||||
module_platform_driver(rk628_rgb_driver);
|
||||
|
||||
MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Rockchip RK628 RGB driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1229,17 +1229,6 @@ config MFD_RK618
|
||||
help
|
||||
if you say yes here you get support for the RK618 from Rockchip.
|
||||
|
||||
config MFD_RK628
|
||||
tristate "Rockchip RK628 MFD Driver"
|
||||
depends on I2C
|
||||
depends on OF
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
select PINCTRL_RK628
|
||||
help
|
||||
if you say yes here you get support for the RK628 from Rockchip.
|
||||
|
||||
config MFD_RK630
|
||||
tristate "RK630 CORE module support"
|
||||
select MFD_CORE
|
||||
|
||||
@@ -226,7 +226,6 @@ obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
|
||||
obj-$(CONFIG_MFD_NTXEC) += ntxec.o
|
||||
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
|
||||
obj-$(CONFIG_MFD_RK618) += rk618.o
|
||||
obj-$(CONFIG_MFD_RK628) += rk628.o
|
||||
obj-$(CONFIG_MFD_RK630) += rk630.o
|
||||
obj-$(CONFIG_MFD_RK630_I2C) += rk630-i2c.o
|
||||
obj-$(CONFIG_MFD_RK630_SPI) += rk630-spi.o
|
||||
|
||||
@@ -1,482 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/rk628.h>
|
||||
|
||||
enum {
|
||||
RK628_IRQ_HDMITX_HPD_HIGH,
|
||||
RK628_IRQ_HDMITX_HPD_LOW,
|
||||
RK628_IRQ_HDMITX,
|
||||
RK628_IRQ_GVI,
|
||||
RK628_IRQ_DSI1,
|
||||
RK628_IRQ_DSI0,
|
||||
RK628_IRQ_CSI,
|
||||
RK628_IRQ_HDMIRX,
|
||||
|
||||
RK628_IRQ_GPIO0,
|
||||
RK628_IRQ_GPIO1,
|
||||
RK628_IRQ_GPIO2,
|
||||
RK628_IRQ_GPIO3,
|
||||
RK628_IRQ_EFUSE,
|
||||
};
|
||||
|
||||
static struct resource rk628_gpio_resources[] = {
|
||||
DEFINE_RES_IRQ(RK628_IRQ_GPIO0),
|
||||
DEFINE_RES_IRQ(RK628_IRQ_GPIO1),
|
||||
DEFINE_RES_IRQ(RK628_IRQ_GPIO2),
|
||||
DEFINE_RES_IRQ(RK628_IRQ_GPIO3),
|
||||
};
|
||||
|
||||
static struct resource rk628_dsi0_resources[] = {
|
||||
DEFINE_RES_IRQ(RK628_IRQ_DSI0),
|
||||
};
|
||||
|
||||
static struct resource rk628_dsi1_resources[] = {
|
||||
DEFINE_RES_IRQ(RK628_IRQ_DSI1),
|
||||
};
|
||||
|
||||
static struct resource rk628_csi_resources[] = {
|
||||
DEFINE_RES_IRQ(RK628_IRQ_CSI),
|
||||
DEFINE_RES_IRQ(RK628_IRQ_HDMIRX),
|
||||
};
|
||||
|
||||
static struct resource rk628_gvi_resources[] = {
|
||||
DEFINE_RES_IRQ(RK628_IRQ_GVI),
|
||||
};
|
||||
|
||||
static struct resource rk628_hdmi_resources[] = {
|
||||
DEFINE_RES_IRQ(RK628_IRQ_HDMITX),
|
||||
DEFINE_RES_IRQ(RK628_IRQ_HDMITX_HPD_HIGH),
|
||||
DEFINE_RES_IRQ(RK628_IRQ_HDMITX_HPD_LOW),
|
||||
};
|
||||
|
||||
static struct resource rk628_hdmirx_resources[] = {
|
||||
DEFINE_RES_IRQ(RK628_IRQ_HDMIRX),
|
||||
};
|
||||
|
||||
static struct resource rk628_efuse_resources[] = {
|
||||
DEFINE_RES_IRQ(RK628_IRQ_EFUSE),
|
||||
};
|
||||
|
||||
static const struct mfd_cell rk628_devs[] = {
|
||||
{
|
||||
.name = "rk628-cru",
|
||||
.of_compatible = "rockchip,rk628-cru",
|
||||
}, {
|
||||
.name = "rk628-pinctrl",
|
||||
.of_compatible = "rockchip,rk628-pinctrl",
|
||||
.resources = rk628_gpio_resources,
|
||||
.num_resources = ARRAY_SIZE(rk628_gpio_resources),
|
||||
}, {
|
||||
.name = "rk628-combrxphy",
|
||||
.of_compatible = "rockchip,rk628-combrxphy",
|
||||
}, {
|
||||
.name = "rk628-combtxphy",
|
||||
.of_compatible = "rockchip,rk628-combtxphy",
|
||||
}, {
|
||||
.name = "rk628-csi",
|
||||
.of_compatible = "rockchip,rk628-csi",
|
||||
.resources = rk628_csi_resources,
|
||||
.num_resources = ARRAY_SIZE(rk628_csi_resources),
|
||||
}, {
|
||||
.name = "rk628-hdmirx",
|
||||
.of_compatible = "rockchip,rk628-hdmirx",
|
||||
.resources = rk628_hdmirx_resources,
|
||||
.num_resources = ARRAY_SIZE(rk628_hdmirx_resources),
|
||||
}, {
|
||||
.name = "rk628-dsi1",
|
||||
.of_compatible = "rockchip,rk628-dsi1",
|
||||
.resources = rk628_dsi1_resources,
|
||||
.num_resources = ARRAY_SIZE(rk628_dsi1_resources),
|
||||
}, {
|
||||
.name = "rk628-dsi0",
|
||||
.of_compatible = "rockchip,rk628-dsi0",
|
||||
.resources = rk628_dsi0_resources,
|
||||
.num_resources = ARRAY_SIZE(rk628_dsi0_resources),
|
||||
}, {
|
||||
.name = "rk628-rgb-tx",
|
||||
.of_compatible = "rockchip,rk628-rgb-tx",
|
||||
}, {
|
||||
.name = "rk628-yuv-rx",
|
||||
.of_compatible = "rockchip,rk628-yuv-rx",
|
||||
}, {
|
||||
.name = "rk628-yuv-tx",
|
||||
.of_compatible = "rockchip,rk628-yuv-tx",
|
||||
}, {
|
||||
.name = "rk628-bt1120-rx",
|
||||
.of_compatible = "rockchip,rk628-bt1120-rx",
|
||||
}, {
|
||||
.name = "rk628-bt1120-tx",
|
||||
.of_compatible = "rockchip,rk628-bt1120-tx",
|
||||
}, {
|
||||
.name = "rk628-lvds",
|
||||
.of_compatible = "rockchip,rk628-lvds",
|
||||
}, {
|
||||
.name = "rk628-gvi",
|
||||
.of_compatible = "rockchip,rk628-gvi",
|
||||
.resources = rk628_gvi_resources,
|
||||
.num_resources = ARRAY_SIZE(rk628_gvi_resources),
|
||||
}, {
|
||||
.name = "rk628-hdmi",
|
||||
.of_compatible = "rockchip,rk628-hdmi",
|
||||
.resources = rk628_hdmi_resources,
|
||||
.num_resources = ARRAY_SIZE(rk628_hdmi_resources),
|
||||
}, {
|
||||
.name = "rk628-efuse",
|
||||
.of_compatible = "rockchip,rk628-efuse",
|
||||
.resources = rk628_efuse_resources,
|
||||
.num_resources = ARRAY_SIZE(rk628_efuse_resources),
|
||||
}, {
|
||||
.name = "rk628-post-process",
|
||||
.of_compatible = "rockchip,rk628-post-process",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_irq rk628_irqs[] = {
|
||||
REGMAP_IRQ_REG(RK628_IRQ_HDMITX_HPD_HIGH, 0, BIT(0)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_HDMITX_HPD_LOW, 0, BIT(1)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_HDMITX, 0, BIT(2)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_GVI, 0, BIT(3)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_DSI1, 0, BIT(4)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_DSI0, 0, BIT(5)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_CSI, 0, BIT(6)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_HDMIRX, 0, BIT(8)),
|
||||
|
||||
REGMAP_IRQ_REG(RK628_IRQ_GPIO0, 4, BIT(0)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_GPIO1, 4, BIT(1)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_GPIO2, 4, BIT(2)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_GPIO3, 4, BIT(3)),
|
||||
REGMAP_IRQ_REG(RK628_IRQ_EFUSE, 4, BIT(4)),
|
||||
};
|
||||
|
||||
static struct rk628_irq_chip_data rk628_irq_chip_data = {
|
||||
.name = "rk628",
|
||||
.irqs = rk628_irqs,
|
||||
.num_irqs = ARRAY_SIZE(rk628_irqs),
|
||||
.num_regs = 2,
|
||||
.irq_reg_stride = (GRF_INTR1_STATUS - GRF_INTR0_STATUS) / 4,
|
||||
.reg_stride = 4,
|
||||
.status_base = GRF_INTR0_STATUS,
|
||||
.mask_base = GRF_INTR0_EN,
|
||||
.ack_base = GRF_INTR0_CLR_EN,
|
||||
};
|
||||
|
||||
static const struct regmap_config rk628_grf_regmap_config = {
|
||||
.name = "grf",
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = GRF_MAX_REGISTER,
|
||||
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
};
|
||||
|
||||
static inline const struct regmap_irq *
|
||||
irq_to_regmap_irq(struct rk628_irq_chip_data *d, int irq)
|
||||
{
|
||||
return &d->irqs[irq];
|
||||
}
|
||||
|
||||
static void rk628_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct rk628_irq_chip_data *d = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&d->lock);
|
||||
}
|
||||
|
||||
static void rk628_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct rk628_irq_chip_data *d = irq_data_get_irq_chip_data(data);
|
||||
int i;
|
||||
u32 reg, mask, val;
|
||||
|
||||
for (i = 0; i < d->num_regs; i++) {
|
||||
reg = d->mask_base + (i * d->reg_stride * d->irq_reg_stride);
|
||||
mask = d->mask_buf_def[i];
|
||||
val = mask << 16 | (~d->mask_buf[i] & mask);
|
||||
regmap_write(d->map, reg, val);
|
||||
}
|
||||
|
||||
mutex_unlock(&d->lock);
|
||||
}
|
||||
|
||||
static void rk628_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct rk628_irq_chip_data *d = irq_data_get_irq_chip_data(data);
|
||||
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
|
||||
|
||||
d->mask_buf[irq_data->reg_offset / d->reg_stride] &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void rk628_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct rk628_irq_chip_data *d = irq_data_get_irq_chip_data(data);
|
||||
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
|
||||
|
||||
d->mask_buf[irq_data->reg_offset / d->reg_stride] |= irq_data->mask;
|
||||
}
|
||||
|
||||
static const struct irq_chip rk628_irq_chip = {
|
||||
.irq_bus_lock = rk628_irq_lock,
|
||||
.irq_bus_sync_unlock = rk628_irq_sync_unlock,
|
||||
.irq_disable = rk628_irq_disable,
|
||||
.irq_enable = rk628_irq_enable,
|
||||
};
|
||||
|
||||
static irqreturn_t rk628_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct rk628_irq_chip_data *d = data;
|
||||
int i;
|
||||
bool handled = false;
|
||||
u32 reg;
|
||||
|
||||
for (i = 0; i < d->num_regs; i++) {
|
||||
reg = d->status_base + (i * d->reg_stride * d->irq_reg_stride);
|
||||
regmap_read(d->map, reg, &d->status_buf[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < d->num_irqs; i++) {
|
||||
if (d->status_buf[d->irqs[i].reg_offset / d->reg_stride] & d->irqs[i].mask) {
|
||||
handle_nested_irq(irq_find_mapping(d->domain, i));
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < d->num_regs; i++) {
|
||||
if (d->status_buf[i]) {
|
||||
reg = d->ack_base + (i * d->reg_stride * d->irq_reg_stride);
|
||||
regmap_write(d->map, reg,
|
||||
d->status_buf[i] << 16 | d->status_buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (handled)
|
||||
return IRQ_HANDLED;
|
||||
else
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int rk628_irq_map(struct irq_domain *h, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
struct rk628_irq_chip_data *d = h->host_data;
|
||||
|
||||
irq_set_chip_data(virq, d);
|
||||
irq_set_chip(virq, &d->irq_chip);
|
||||
irq_set_nested_thread(virq, 1);
|
||||
irq_set_parent(virq, d->irq);
|
||||
irq_set_noprobe(virq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops rk628_irq_domain_ops = {
|
||||
.map = rk628_irq_map,
|
||||
.xlate = irq_domain_xlate_onetwocell,
|
||||
};
|
||||
|
||||
static int rk628_irq_init(struct rk628 *rk628, int irq)
|
||||
{
|
||||
struct device *dev = rk628->dev;
|
||||
struct rk628_irq_chip_data *d = rk628->irq_data;
|
||||
struct regmap *map = rk628->grf;
|
||||
u32 reg, mask, val;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (d->num_regs <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
d->status_buf = devm_kcalloc(dev, d->num_regs, sizeof(unsigned int),
|
||||
GFP_KERNEL);
|
||||
if (!d->status_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
d->mask_buf = devm_kcalloc(dev, d->num_regs, sizeof(unsigned int),
|
||||
GFP_KERNEL);
|
||||
if (!d->mask_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
d->mask_buf_def = devm_kcalloc(dev, d->num_regs, sizeof(unsigned int),
|
||||
GFP_KERNEL);
|
||||
if (!d->mask_buf_def)
|
||||
return -ENOMEM;
|
||||
|
||||
d->irq_chip = rk628_irq_chip;
|
||||
d->irq_chip.name = d->name;
|
||||
d->irq = irq;
|
||||
d->map = map;
|
||||
|
||||
mutex_init(&d->lock);
|
||||
|
||||
for (i = 0; i < d->num_irqs; i++)
|
||||
d->mask_buf_def[d->irqs[i].reg_offset / d->reg_stride] |= d->irqs[i].mask;
|
||||
|
||||
/* Mask all the interrupts by default */
|
||||
for (i = 0; i < d->num_regs; i++) {
|
||||
d->mask_buf[i] = d->mask_buf_def[i];
|
||||
reg = d->mask_base + (i * d->reg_stride * d->irq_reg_stride);
|
||||
mask = d->mask_buf[i];
|
||||
val = mask << 16 | (~d->mask_buf[i] & mask);
|
||||
regmap_write(d->map, reg, val);
|
||||
}
|
||||
|
||||
d->domain = irq_domain_add_linear(dev->of_node, d->num_irqs,
|
||||
&rk628_irq_domain_ops, d);
|
||||
if (!d->domain) {
|
||||
dev_err(dev, "Failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL, rk628_irq_thread,
|
||||
IRQF_ONESHOT, d->name, d);
|
||||
if (ret != 0) {
|
||||
irq_domain_remove(d->domain);
|
||||
dev_err(dev, "Failed to request IRQ %d: %d\n", irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk628_irq_exit(struct rk628 *rk628)
|
||||
{
|
||||
struct rk628_irq_chip_data *d = rk628->irq_data;
|
||||
unsigned int virq;
|
||||
int hwirq;
|
||||
|
||||
/* Dispose all virtual irq from irq domain before removing it */
|
||||
for (hwirq = 0; hwirq < d->num_irqs; hwirq++) {
|
||||
/* Ignore hwirq if holes in the IRQ list */
|
||||
if (!d->irqs[hwirq].mask)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Find the virtual irq of hwirq on chip and if it is
|
||||
* there then dispose it
|
||||
*/
|
||||
virq = irq_find_mapping(d->domain, hwirq);
|
||||
if (virq)
|
||||
irq_dispose_mapping(virq);
|
||||
}
|
||||
|
||||
irq_domain_remove(d->domain);
|
||||
}
|
||||
|
||||
static int
|
||||
rk628_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct rk628 *rk628;
|
||||
int ret;
|
||||
|
||||
rk628 = devm_kzalloc(dev, sizeof(*rk628), GFP_KERNEL);
|
||||
if (!rk628)
|
||||
return -ENOMEM;
|
||||
|
||||
rk628->dev = dev;
|
||||
rk628->client = client;
|
||||
rk628->irq_data = &rk628_irq_chip_data;
|
||||
i2c_set_clientdata(client, rk628);
|
||||
|
||||
rk628->enable_gpio = devm_gpiod_get_optional(dev, "enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(rk628->enable_gpio)) {
|
||||
ret = PTR_ERR(rk628->enable_gpio);
|
||||
dev_err(dev, "failed to request enable GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rk628->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(rk628->reset_gpio)) {
|
||||
ret = PTR_ERR(rk628->reset_gpio);
|
||||
dev_err(dev, "failed to request reset GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiod_set_value(rk628->enable_gpio, 1);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value(rk628->reset_gpio, 0);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value(rk628->reset_gpio, 1);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value(rk628->reset_gpio, 0);
|
||||
usleep_range(10000, 11000);
|
||||
|
||||
rk628->grf = devm_regmap_init_i2c(client, &rk628_grf_regmap_config);
|
||||
if (IS_ERR(rk628->grf)) {
|
||||
ret = PTR_ERR(rk628->grf);
|
||||
dev_err(dev, "failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* selete int io function */
|
||||
ret = regmap_write(rk628->grf, GRF_GPIO3AB_SEL_CON, 0x30002000);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to access register: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rk628_irq_init(rk628, client->irq);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add IRQ chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(dev, PLATFORM_DEVID_NONE,
|
||||
rk628_devs, ARRAY_SIZE(rk628_devs),
|
||||
NULL, 0, rk628->irq_data->domain);
|
||||
if (ret) {
|
||||
rk628_irq_exit(rk628);
|
||||
dev_err(dev, "Failed to add MFD children: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk628_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct rk628 *rk628 = i2c_get_clientdata(client);
|
||||
|
||||
mfd_remove_devices(rk628->dev);
|
||||
rk628_irq_exit(rk628);
|
||||
}
|
||||
|
||||
static const struct of_device_id rk628_of_match[] = {
|
||||
{ .compatible = "rockchip,rk628", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk628_of_match);
|
||||
|
||||
static const struct i2c_device_id rk628_i2c_id[] = {
|
||||
{ "rk628", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rk628_i2c_id);
|
||||
|
||||
static struct i2c_driver rk628_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "rk628",
|
||||
.of_match_table = of_match_ptr(rk628_of_match),
|
||||
},
|
||||
.probe = rk628_i2c_probe,
|
||||
.remove = rk628_i2c_remove,
|
||||
.id_table = rk628_i2c_id,
|
||||
};
|
||||
module_i2c_driver(rk628_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Rockchip RK628 MFD driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -218,18 +218,6 @@ config NVMEM_RAVE_SP_EEPROM
|
||||
help
|
||||
Say y here to enable Rave SP EEPROM support.
|
||||
|
||||
config NVMEM_RK628_EFUSE
|
||||
tristate "RK628 eFuse Support"
|
||||
depends on ARCH_ROCKCHIP || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
depends on MFD_RK628
|
||||
help
|
||||
This is a simple drive to dump specified values of Rk628 SoC
|
||||
from eFuse, such as cpu-leakage.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called nvmem_rk628_efuse.
|
||||
|
||||
config NVMEM_RMEM
|
||||
tristate "Reserved Memory Based Driver Support"
|
||||
depends on HAS_IOMEM
|
||||
|
||||
@@ -45,8 +45,6 @@ obj-$(CONFIG_NVMEM_QCOM_QFPROM) += nvmem_qfprom.o
|
||||
nvmem_qfprom-y := qfprom.o
|
||||
obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o
|
||||
nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o
|
||||
obj-$(CONFIG_NVMEM_RK628_EFUSE) += nvmem_rk628_efuse.o
|
||||
nvmem_rk628_efuse-y := rk628-efuse.o
|
||||
obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o
|
||||
nvmem-rmem-y := rmem.o
|
||||
obj-$(CONFIG_NVMEM_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o
|
||||
|
||||
@@ -1,299 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* RK628 eFuse Driver
|
||||
*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Weixin Zhou <zwx@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/rk628.h>
|
||||
|
||||
#define EFUSE_SIZE 64
|
||||
|
||||
#define T_CSB_P_S 0
|
||||
#define T_PGENB_P_S (15 + 200)
|
||||
#define T_LOAD_P_S 0
|
||||
#define T_ADDR_P_S (15 + 200 + 5)
|
||||
#define T_STROBE_P_S ((150 + 2000 + 100) / 9)
|
||||
#define T_CSB_P_L 0
|
||||
#define T_PGENB_P_L (15 + 200 + 10 + 200 + 190 + 10)
|
||||
#define T_LOAD_P_L (15 + 200 + 200 + 190 + 10 + 100 + 15)
|
||||
#define T_ADDR_P_L (15 + 200 + 5 + 200 + 5)
|
||||
#define T_STROBE_P_L ((150 + 2000 + 100 + 2000) / 9)
|
||||
#define T_CSB_R_S 0
|
||||
#define T_PGENB_R_S 0
|
||||
#define T_LOAD_R_S 15
|
||||
#define T_ADDR_R_S (15 + 9)
|
||||
#define T_STROBE_R_S ((150 + 100) / 9)
|
||||
#define T_CSB_R_L 0
|
||||
#define T_PGENB_R_L 0
|
||||
#define T_LOAD_R_L (15 + 5 + 5 + 10 + 15)
|
||||
#define T_ADDR_R_L (15 + 10 + 5 + 1)
|
||||
#define T_STROBE_R_L ((150 + 100 + 50) / 8)
|
||||
|
||||
#define T_CSB_P 0x28
|
||||
#define T_PGENB_P 0x2c
|
||||
#define T_LOAD_P 0x30
|
||||
#define T_ADDR_P 0x34
|
||||
#define T_STROBE_P 0x38
|
||||
#define T_CSB_R 0x3c
|
||||
#define T_PGENB_R 0x40
|
||||
#define T_LOAD_R 0x44
|
||||
#define T_ADDR_R 0x48
|
||||
#define T_STROBE_R 0x4c
|
||||
#define EFUSE_REVISION 0x50
|
||||
|
||||
#define RK628_EFUSE_BASE 0xb0000
|
||||
#define RK628_MOD 0x00
|
||||
#define RK628_INT_STATUS 0x0018
|
||||
#define RK628_DOUT 0x0020
|
||||
#define RK628_AUTO_CTRL 0x0024
|
||||
#define RK628_USER_MODE BIT(0)
|
||||
#define RK628_INT_FINISH BIT(0)
|
||||
#define RK628_AUTO_ENB BIT(0)
|
||||
#define RK628_AUTO_RD BIT(1)
|
||||
#define RK628_ADDR_ROW 16
|
||||
#define RK628_ADDR_COL 22
|
||||
#define RK628_A_SHIFT 16
|
||||
#define RK628_A_MASK 0x3ff
|
||||
#define RK628_NBYTES 1
|
||||
|
||||
#define REG_EFUSE_CTRL 0x0000
|
||||
#define REG_EFUSE_DOUT 0x0004
|
||||
|
||||
struct rk628_efuse_chip {
|
||||
struct device *dev;
|
||||
u32 base;
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
struct gpio_desc *avdd_gpio;
|
||||
};
|
||||
|
||||
static int rk628_read(struct regmap *regmap, u32 reg)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
struct rk628_efuse_chip *efuse = container_of(regmap, struct rk628_efuse_chip, regmap);
|
||||
|
||||
ret = regmap_read(regmap, reg, &val);
|
||||
if (ret) {
|
||||
dev_err(efuse->dev, "rk628-efuse:failed to read reg 0x%x\n", reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int rk628_write(struct regmap *regmap, u32 val, u32 reg)
|
||||
{
|
||||
int ret;
|
||||
struct rk628_efuse_chip *efuse = container_of(regmap, struct rk628_efuse_chip, regmap);
|
||||
|
||||
ret = regmap_write(regmap, reg, val);
|
||||
if (ret)
|
||||
dev_err(efuse->dev, "rk628-efuse:failed to write reg 0x%x\n", reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rk628_efuse_timing_init(struct rk628_efuse_chip *efuse)
|
||||
{
|
||||
u32 base = efuse->base;
|
||||
/* enable auto mode */
|
||||
rk628_write(efuse->regmap,
|
||||
rk628_read(efuse->regmap, base + RK628_MOD) & (~RK628_USER_MODE),
|
||||
base + RK628_MOD);
|
||||
|
||||
/* setup efuse timing */
|
||||
rk628_write(efuse->regmap, (T_CSB_P_S << 16) | T_CSB_P_L, base + T_CSB_P);
|
||||
rk628_write(efuse->regmap, (T_PGENB_P_S << 16) | T_PGENB_P_L, base + T_PGENB_P);
|
||||
rk628_write(efuse->regmap, (T_LOAD_P_S << 16) | T_LOAD_P_L, base + T_LOAD_P);
|
||||
rk628_write(efuse->regmap, (T_ADDR_P_S << 16) | T_ADDR_P_L, base + T_ADDR_P);
|
||||
rk628_write(efuse->regmap, (T_STROBE_P_S << 16) | T_STROBE_P_L, base + T_STROBE_P);
|
||||
rk628_write(efuse->regmap, (T_CSB_R_S << 16) | T_CSB_R_L, base + T_CSB_R);
|
||||
rk628_write(efuse->regmap, (T_PGENB_R_S << 16) | T_PGENB_R_L, base + T_PGENB_R);
|
||||
rk628_write(efuse->regmap, (T_LOAD_R_S << 16) | T_LOAD_R_L, base + T_LOAD_R);
|
||||
rk628_write(efuse->regmap, (T_ADDR_R_S << 16) | T_ADDR_R_L, base + T_ADDR_R);
|
||||
rk628_write(efuse->regmap, (T_STROBE_R_S << 16) | T_STROBE_R_L, base + T_STROBE_R);
|
||||
}
|
||||
|
||||
static void rk628_efuse_timing_deinit(struct rk628_efuse_chip *efuse)
|
||||
{
|
||||
u32 base = efuse->base;
|
||||
/* disable auto mode */
|
||||
rk628_write(efuse->regmap,
|
||||
rk628_read(efuse->regmap, base + RK628_MOD) | RK628_USER_MODE, base + RK628_MOD);
|
||||
|
||||
/* clear efuse timing */
|
||||
rk628_write(efuse->regmap, 0, base + T_CSB_P);
|
||||
rk628_write(efuse->regmap, 0, base + T_PGENB_P);
|
||||
rk628_write(efuse->regmap, 0, base + T_LOAD_P);
|
||||
rk628_write(efuse->regmap, 0, base + T_ADDR_P);
|
||||
rk628_write(efuse->regmap, 0, base + T_STROBE_P);
|
||||
rk628_write(efuse->regmap, 0, base + T_CSB_R);
|
||||
rk628_write(efuse->regmap, 0, base + T_PGENB_R);
|
||||
rk628_write(efuse->regmap, 0, base + T_LOAD_R);
|
||||
rk628_write(efuse->regmap, 0, base + T_ADDR_R);
|
||||
rk628_write(efuse->regmap, 0, base + T_STROBE_R);
|
||||
}
|
||||
|
||||
static int rk628_efuse_read(void *context, unsigned int offset,
|
||||
void *val, size_t bytes)
|
||||
{
|
||||
struct rk628_efuse_chip *efuse = context;
|
||||
unsigned int addr_start, addr_end, addr_offset, addr_len;
|
||||
u32 out_value, status;
|
||||
u8 *buf;
|
||||
int ret, i = 0;
|
||||
|
||||
ret = clk_prepare_enable(efuse->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(efuse->dev, "failed to prepare/enable efuse pclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
addr_start = rounddown(offset, RK628_NBYTES) / RK628_NBYTES;
|
||||
addr_end = roundup(offset + bytes, RK628_NBYTES) / RK628_NBYTES;
|
||||
addr_offset = offset % RK628_NBYTES;
|
||||
addr_len = addr_end - addr_start;
|
||||
|
||||
buf = kzalloc(sizeof(*buf) * addr_len * RK628_NBYTES, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
rk628_efuse_timing_init(efuse);
|
||||
|
||||
while (addr_len--) {
|
||||
rk628_write(efuse->regmap, RK628_AUTO_RD | RK628_AUTO_ENB |
|
||||
((addr_start++ & RK628_A_MASK) << RK628_A_SHIFT),
|
||||
efuse->base + RK628_AUTO_CTRL);
|
||||
udelay(2);
|
||||
status = rk628_read(efuse->regmap, efuse->base + RK628_INT_STATUS);
|
||||
if (!(status & RK628_INT_FINISH)) {
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
out_value = rk628_read(efuse->regmap, efuse->base + RK628_DOUT);
|
||||
rk628_write(efuse->regmap, RK628_INT_FINISH, efuse->base + RK628_INT_STATUS);
|
||||
|
||||
memcpy(&buf[i], &out_value, RK628_NBYTES);
|
||||
i += RK628_NBYTES;
|
||||
}
|
||||
memcpy(val, buf + addr_offset, bytes);
|
||||
err:
|
||||
rk628_efuse_timing_deinit(efuse);
|
||||
kfree(buf);
|
||||
nomem:
|
||||
clk_disable_unprepare(efuse->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct nvmem_config econfig = {
|
||||
.name = "rk628-efuse",
|
||||
.owner = THIS_MODULE,
|
||||
.stride = 1,
|
||||
.word_size = 1,
|
||||
.read_only = true,
|
||||
};
|
||||
|
||||
static const struct regmap_range rk628_efuse_readable_ranges[] = {
|
||||
regmap_reg_range(RK628_EFUSE_BASE, RK628_EFUSE_BASE + EFUSE_REVISION),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table rk628_efuse_readable_table = {
|
||||
.yes_ranges = rk628_efuse_readable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(rk628_efuse_readable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config rk628_efuse_regmap_config = {
|
||||
.name = "rk628-efuse",
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = RK628_EFUSE_BASE + EFUSE_REVISION,
|
||||
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.rd_table = &rk628_efuse_readable_table,
|
||||
};
|
||||
|
||||
static const struct of_device_id rk628_efuse_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk628-efuse",
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk628_efuse_match);
|
||||
|
||||
static int __init rk628_efuse_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct nvmem_device *nvmem;
|
||||
struct rk628_efuse_chip *efuse;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent);
|
||||
int ret;
|
||||
|
||||
efuse = devm_kzalloc(&pdev->dev, sizeof(struct rk628_efuse_chip),
|
||||
GFP_KERNEL);
|
||||
if (!efuse)
|
||||
return -ENOMEM;
|
||||
|
||||
efuse->regmap = devm_regmap_init_i2c(rk628->client,
|
||||
&rk628_efuse_regmap_config);
|
||||
if (IS_ERR(efuse->regmap)) {
|
||||
ret = PTR_ERR(efuse->regmap);
|
||||
dev_err(dev, "failed to allocate register map: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
efuse->clk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (IS_ERR(efuse->clk)) {
|
||||
dev_err(dev, "failed to get pclk: %ld\n", PTR_ERR(efuse->clk));
|
||||
return PTR_ERR(efuse->clk);
|
||||
}
|
||||
|
||||
efuse->avdd_gpio = devm_gpiod_get_optional(dev, "efuse", GPIOD_OUT_LOW);
|
||||
efuse->base = RK628_EFUSE_BASE;
|
||||
efuse->dev = &pdev->dev;
|
||||
econfig.size = EFUSE_SIZE;
|
||||
econfig.reg_read = (void *)&rk628_efuse_read;
|
||||
econfig.priv = efuse;
|
||||
econfig.dev = efuse->dev;
|
||||
nvmem = devm_nvmem_register(&econfig);
|
||||
if (IS_ERR(nvmem))
|
||||
return PTR_ERR(nvmem);
|
||||
|
||||
platform_set_drvdata(pdev, nvmem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rk628_efuse_driver = {
|
||||
.probe = rk628_efuse_probe,
|
||||
.driver = {
|
||||
.name = "rk628-efuse",
|
||||
.of_match_table = rk628_efuse_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(rk628_efuse_driver);
|
||||
|
||||
MODULE_DESCRIPTION("rk628_efuse driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -414,16 +414,6 @@ config PINCTRL_PISTACHIO
|
||||
help
|
||||
This support pinctrl and GPIO driver for IMG Pistachio SoC.
|
||||
|
||||
config PINCTRL_RK628
|
||||
tristate "Pinctrl and GPIO driver for RK628 PMIC"
|
||||
depends on MFD_RK628
|
||||
select GPIOLIB
|
||||
select PINMUX
|
||||
select GENERIC_PINCONF
|
||||
select REGMAP_IRQ
|
||||
help
|
||||
This selects the pinctrl driver for RK628.
|
||||
|
||||
config PINCTRL_RK805
|
||||
tristate "Pinctrl and GPIO driver for RK805 PMIC"
|
||||
depends on MFD_RK808
|
||||
|
||||
@@ -42,7 +42,6 @@ obj-$(CONFIG_PINCTRL_OXNAS) += pinctrl-oxnas.o
|
||||
obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o
|
||||
obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o
|
||||
obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
|
||||
obj-$(CONFIG_PINCTRL_RK628) += pinctrl-rk628.o
|
||||
obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o
|
||||
obj-$(CONFIG_PINCTRL_RK806) += pinctrl-rk806.o
|
||||
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,272 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef _RK628_H
|
||||
#define _RK628_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
|
||||
#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16))
|
||||
|
||||
#define GRF_SYSTEM_CON0 0x0000
|
||||
#define SW_VSYNC_POL_MASK BIT(26)
|
||||
#define SW_VSYNC_POL(x) UPDATE(x, 26, 26)
|
||||
#define SW_HSYNC_POL_MASK BIT(25)
|
||||
#define SW_HSYNC_POL(x) UPDATE(x, 25, 25)
|
||||
#define SW_ADAPTER_I2CSLADR_MASK GENMASK(24, 22)
|
||||
#define SW_ADAPTER_I2CSLADR(x) UPDATE(x, 24, 22)
|
||||
#define SW_EDID_MODE_MASK BIT(21)
|
||||
#define SW_EDID_MODE(x) UPDATE(x, 21, 21)
|
||||
#define SW_I2S_DATA_OEN_MASK BIT(10)
|
||||
#define SW_I2S_DATA_OEN(x) UPDATE(x, 10, 10)
|
||||
#define SW_BT_DATA_OEN_MASK BIT(9)
|
||||
#define SW_BT_DATA_OEN BIT(9)
|
||||
#define SW_EFUSE_HDCP_EN_MASK BIT(8)
|
||||
#define SW_EFUSE_HDCP_EN(x) UPDATE(x, 8, 8)
|
||||
#define SW_OUTPUT_MODE_MASK GENMASK(7, 3)
|
||||
#define SW_OUTPUT_MODE(x) UPDATE(x, 7, 3)
|
||||
#define SW_INPUT_MODE_MASK GENMASK(2, 0)
|
||||
#define SW_INPUT_MODE(x) UPDATE(x, 2, 0)
|
||||
#define GRF_SYSTEM_CON1 0x0004
|
||||
#define GRF_SYSTEM_CON2 0x0008
|
||||
#define GRF_SYSTEM_CON3 0x000c
|
||||
#define GRF_GPIO_RX_CEC_SEL_MASK BIT(7)
|
||||
#define GRF_GPIO_RX_CEC_SEL(x) UPDATE(x, 7, 7)
|
||||
#define GRF_GPIO_RXDDC_SDA_SEL_MASK BIT(6)
|
||||
#define GRF_GPIO_RXDDC_SDA_SEL(x) UPDATE(x, 6, 6)
|
||||
#define GRF_GPIO_RXDDC_SCL_SEL_MASK BIT(5)
|
||||
#define GRF_GPIO_RXDDC_SCL_SEL(x) UPDATE(x, 5, 5)
|
||||
#define GRF_SCALER_CON0 0x0010
|
||||
#define SCL_VER_DOWN_MODE(x) HIWORD_UPDATE(x, 8, 8)
|
||||
#define SCL_HOR_DOWN_MODE(x) HIWORD_UPDATE(x, 7, 7)
|
||||
#define SCL_BIC_COE_SEL(x) HIWORD_UPDATE(x, 6, 5)
|
||||
#define SCL_VER_MODE(x) HIWORD_UPDATE(x, 4, 3)
|
||||
#define SCL_HOR_MODE(x) HIWORD_UPDATE(x, 2, 1)
|
||||
#define SCL_EN(x) HIWORD_UPDATE(x, 0, 0)
|
||||
#define GRF_SCALER_CON1 0x0014
|
||||
#define SCL_V_FACTOR(x) UPDATE(x, 31, 16)
|
||||
#define SCL_H_FACTOR(x) UPDATE(x, 15, 0)
|
||||
#define GRF_SCALER_CON2 0x0018
|
||||
#define DSP_FRAME_VST(x) UPDATE(x, 28, 16)
|
||||
#define DSP_FRAME_HST(x) UPDATE(x, 12, 0)
|
||||
#define GRF_SCALER_CON3 0x001c
|
||||
#define DSP_HS_END(x) UPDATE(x, 23, 16)
|
||||
#define DSP_HTOTAL(x) UPDATE(x, 12, 0)
|
||||
#define GRF_SCALER_CON4 0x0020
|
||||
#define DSP_HACT_ST(x) UPDATE(x, 28, 16)
|
||||
#define DSP_HACT_END(x) UPDATE(x, 12, 0)
|
||||
#define GRF_SCALER_CON5 0x0024
|
||||
#define DSP_VS_END(x) UPDATE(x, 23, 16)
|
||||
#define DSP_VTOTAL(x) UPDATE(x, 12, 0)
|
||||
#define GRF_SCALER_CON6 0x0028
|
||||
#define DSP_VACT_ST(x) UPDATE(x, 28, 16)
|
||||
#define DSP_VACT_END(x) UPDATE(x, 12, 0)
|
||||
#define GRF_SCALER_CON7 0x002c
|
||||
#define DSP_HBOR_ST(x) UPDATE(x, 28, 16)
|
||||
#define DSP_HBOR_END(x) UPDATE(x, 12, 0)
|
||||
#define GRF_SCALER_CON8 0x0030
|
||||
#define DSP_VBOR_ST(x) UPDATE(x, 28, 16)
|
||||
#define DSP_VBOR_END(x) UPDATE(x, 12, 0)
|
||||
#define GRF_POST_PROC_CON 0x0034
|
||||
#define SW_DCLK_OUT_INV_EN BIT(9)
|
||||
#define SW_DCLK_IN_INV_EN BIT(8)
|
||||
#define SW_TXPHY_REFCLK_SEL_MASK GENMASK(6, 5)
|
||||
#define SW_TXPHY_REFCLK_SEL(x) UPDATE(x, 6, 5)
|
||||
#define SW_HDMITX_VCLK_PLLREF_SEL_MASK BIT(4)
|
||||
#define SW_HDMITX_VCLK_PLLREF_SEL(x) UPDATE(x, 4, 4)
|
||||
#define SW_HDMITX_DCLK_INV_EN BIT(3)
|
||||
#define SW_SPLIT_MODE(x) UPDATE(x, 1, 1)
|
||||
#define SW_SPLIT_EN BIT(0)
|
||||
#define GRF_CSC_CTRL_CON 0x0038
|
||||
#define SW_YUV2VYU_SWP(x) HIWORD_UPDATE(x, 8, 8)
|
||||
#define SW_R2Y_EN(x) HIWORD_UPDATE(x, 4, 4)
|
||||
#define SW_Y2R_EN(x) HIWORD_UPDATE(x, 0, 0)
|
||||
#define GRF_LVDS_TX_CON 0x003c
|
||||
#define SW_LVDS_CON_DUAL_SEL(x) HIWORD_UPDATE(x, 12, 12)
|
||||
#define SW_LVDS_CON_DEN_POLARITY(x) HIWORD_UPDATE(x, 11, 11)
|
||||
#define SW_LVDS_CON_HS_POLARITY(x) HIWORD_UPDATE(x, 10, 10)
|
||||
#define SW_LVDS_CON_CLKINV(x) HIWORD_UPDATE(x, 9, 9)
|
||||
#define SW_LVDS_STARTPHASE(x) HIWORD_UPDATE(x, 8, 8)
|
||||
#define SW_LVDS_CON_STARTSEL(x) HIWORD_UPDATE(x, 7, 7)
|
||||
#define SW_LVDS_CON_CHASEL(x) HIWORD_UPDATE(x, 6, 6)
|
||||
#define SW_LVDS_TIE_VSYNC_VALUE(x) HIWORD_UPDATE(x, 5, 5)
|
||||
#define SW_LVDS_TIE_HSYNC_VALUE(x) HIWORD_UPDATE(x, 4, 4)
|
||||
#define SW_LVDS_TIE_DEN_ONLY(x) HIWORD_UPDATE(x, 3, 3)
|
||||
#define SW_LVDS_CON_MSBSEL(x) HIWORD_UPDATE(x, 2, 2)
|
||||
#define SW_LVDS_CON_SELECT(x) HIWORD_UPDATE(x, 1, 0)
|
||||
#define GRF_RGB_DEC_CON0 0x0040
|
||||
#define SW_HRES_MASK GENMASK(28, 16)
|
||||
#define SW_HRES(x) UPDATE(x, 28, 16)
|
||||
#define DUAL_DATA_SWAP BIT(6)
|
||||
#define DEC_DUALEDGE_EN BIT(5)
|
||||
#define SW_PROGRESS_EN BIT(4)
|
||||
#define SW_YC_SWAP BIT(3)
|
||||
#define SW_CAP_EN_ASYNC BIT(1)
|
||||
#define SW_CAP_EN_PSYNC BIT(0)
|
||||
#define GRF_RGB_DEC_CON1 0x0044
|
||||
#define SW_SET_X_MASK GENMASK(28, 16)
|
||||
#define SW_SET_X(x) HIWORD_UPDATE(x, 28, 16)
|
||||
#define SW_SET_Y_MASK GENMASK(28, 16)
|
||||
#define SW_SET_Y(x) HIWORD_UPDATE(x, 28, 16)
|
||||
#define GRF_RGB_DEC_CON2 0x0048
|
||||
#define GRF_RGB_ENC_CON 0x004c
|
||||
#define BT1120_UV_SWAP(x) HIWORD_UPDATE(x, 5, 5)
|
||||
#define ENC_DUALEDGE_EN(x) HIWORD_UPDATE(x, 3, 3)
|
||||
#define GRF_MIPI_LANE_DELAY_CON0 0x0050
|
||||
#define GRF_MIPI_LANE_DELAY_CON1 0x0054
|
||||
#define GRF_BT1120_DCLK_DELAY_CON0 0x0058
|
||||
#define GRF_BT1120_DCLK_DELAY_CON1 0x005c
|
||||
#define GRF_MIPI_TX0_CON 0x0060
|
||||
#define DPIUPDATECFG BIT(26)
|
||||
#define DPICOLORM BIT(25)
|
||||
#define DPISHUTDN BIT(24)
|
||||
#define CSI_PHYRSTZ BIT(21)
|
||||
#define CSI_PHYSHUTDOWNZ BIT(20)
|
||||
#define FORCETXSTOPMODE_MASK GENMASK(19, 16)
|
||||
#define FORCETXSTOPMODE(x) UPDATE(x, 19, 16)
|
||||
#define FORCERXMODE_MASK GENMASK(15, 12)
|
||||
#define FORCERXMODE(x) UPDATE(x, 15, 12)
|
||||
#define PHY_TESTCLR BIT(10)
|
||||
#define PHY_TESTCLK BIT(9)
|
||||
#define PHY_TESTEN BIT(8)
|
||||
#define PHY_TESTDIN_MASK GENMASK(7, 0)
|
||||
#define PHY_TESTDIN(x) UPDATE(x, 7, 0)
|
||||
#define GRF_DPHY0_STATUS 0x0064
|
||||
#define DPHY_PHYLOCK BIT(24)
|
||||
#define PHY_TESTDOUT_SHIFT 8
|
||||
#define GRF_MIPI_TX1_CON 0x0068
|
||||
#define GRF_DPHY1_STATUS 0x006c
|
||||
#define GRF_GPIO0AB_SEL_CON 0x0070
|
||||
#define GRF_GPIO1AB_SEL_CON 0x0074
|
||||
#define GRF_GPIO2AB_SEL_CON 0x0078
|
||||
#define GRF_GPIO2C_SEL_CON 0x007c
|
||||
#define GRF_GPIO3AB_SEL_CON 0x0080
|
||||
#define GRF_GPIO2A_SMT 0x0090
|
||||
#define GRF_GPIO2B_SMT 0x0094
|
||||
#define GRF_GPIO2C_SMT 0x0098
|
||||
#define GRF_GPIO3AB_SMT 0x009c
|
||||
#define GRF_GPIO0A_P_CON 0x00a0
|
||||
#define GRF_GPIO1A_P_CON 0x00a4
|
||||
#define GRF_GPIO2A_P_CON 0x00a8
|
||||
#define GRF_GPIO2B_P_CON 0x00ac
|
||||
#define GRF_GPIO2C_P_CON 0x00b0
|
||||
#define GRF_GPIO3A_P_CON 0x00b4
|
||||
#define GRF_GPIO3B_P_CON 0x00b8
|
||||
#define GRF_GPIO0B_D_CON 0x00c0
|
||||
#define GRF_GPIO1B_D_CON 0x00c4
|
||||
#define GRF_GPIO2A_D0_CON 0x00c8
|
||||
#define GRF_GPIO2A_D1_CON 0x00cc
|
||||
#define GRF_GPIO2B_D0_CON 0x00d0
|
||||
#define GRF_GPIO2B_D1_CON 0x00d4
|
||||
#define GRF_GPIO2C_D0_CON 0x00d8
|
||||
#define GRF_GPIO2C_D1_CON 0x00dc
|
||||
#define GRF_GPIO3A_D0_CON 0x00e0
|
||||
#define GRF_GPIO3A_D1_CON 0x00e4
|
||||
#define GRF_GPIO3B_D_CON 0x00e8
|
||||
#define GRF_GPIO_SR_CON 0x00ec
|
||||
#define GRF_INTR0_EN 0x0100
|
||||
#define GRF_INTR0_CLR_EN 0x0104
|
||||
#define GRF_INTR0_STATUS 0x0108
|
||||
#define GRF_INTR0_RAW_STATUS 0x010c
|
||||
#define GRF_INTR1_EN 0x0110
|
||||
#define GRF_INTR1_CLR_EN 0x0114
|
||||
#define GRF_INTR1_STATUS 0x0118
|
||||
#define GRF_INTR1_RAW_STATUS 0x011c
|
||||
#define GRF_SYSTEM_STATUS0 0x0120
|
||||
/* 0: i2c mode and mcu mode; 1: i2c mode only */
|
||||
#define I2C_ONLY_FLAG BIT(6)
|
||||
#define GRF_SYSTEM_STATUS3 0x012c
|
||||
#define GRF_SYSTEM_STATUS4 0x0130
|
||||
#define GRF_OS_REG0 0x0140
|
||||
#define GRF_OS_REG1 0x0144
|
||||
#define GRF_OS_REG2 0x0148
|
||||
#define GRF_OS_REG3 0x014c
|
||||
#define GRF_SOC_VERSION 0x0150
|
||||
#define GRF_MAX_REGISTER GRF_SOC_VERSION
|
||||
|
||||
enum {
|
||||
COMBTXPHY_MODULEA_EN = BIT(0),
|
||||
COMBTXPHY_MODULEB_EN = BIT(1),
|
||||
};
|
||||
|
||||
enum {
|
||||
OUTPUT_MODE_GVI = 1,
|
||||
OUTPUT_MODE_LVDS,
|
||||
OUTPUT_MODE_HDMI,
|
||||
OUTPUT_MODE_CSI,
|
||||
OUTPUT_MODE_DSI,
|
||||
OUTPUT_MODE_BT1120 = 8,
|
||||
OUTPUT_MODE_RGB = 16,
|
||||
OUTPUT_MODE_YUV = 24,
|
||||
};
|
||||
|
||||
enum {
|
||||
INPUT_MODE_HDMI,
|
||||
INPUT_MODE_BT1120 = 2,
|
||||
INPUT_MODE_RGB,
|
||||
INPUT_MODE_YUV,
|
||||
};
|
||||
|
||||
struct rk628_irq_chip_data {
|
||||
const char *name;
|
||||
unsigned int status_base;
|
||||
unsigned int mask_base;
|
||||
unsigned int ack_base;
|
||||
int num_regs;
|
||||
const struct regmap_irq *irqs;
|
||||
int num_irqs;
|
||||
struct mutex lock;
|
||||
struct irq_chip irq_chip;
|
||||
struct regmap *map;
|
||||
struct irq_domain *domain;
|
||||
int irq;
|
||||
unsigned int *status_buf;
|
||||
unsigned int *mask_buf;
|
||||
unsigned int *mask_buf_def;
|
||||
unsigned int irq_reg_stride;
|
||||
unsigned int reg_stride;
|
||||
};
|
||||
|
||||
struct rk628 {
|
||||
struct device *dev;
|
||||
struct i2c_client *client;
|
||||
struct regmap *grf;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct rk628_irq_chip_data *irq_data;
|
||||
struct drm_display_mode src_mode;
|
||||
struct drm_display_mode dst_mode;
|
||||
bool dst_mode_valid;
|
||||
};
|
||||
|
||||
/**
|
||||
* rk628_scaler_add_src_mode - add source mode for scaler
|
||||
* @rk628: parent device
|
||||
* @connector: DRM connector
|
||||
* If need scale, call the function at last of get_modes.
|
||||
*/
|
||||
int rk628_scaler_add_src_mode(struct rk628 *rk628,
|
||||
struct drm_connector *connector);
|
||||
|
||||
/**
|
||||
* rk628_mode_copy - rk628 mode copy
|
||||
* @rk628: parent device
|
||||
* @dst: dst mode
|
||||
* @src: src mode
|
||||
* Call the function at mode_set, replace drm_mode_copy.
|
||||
*/
|
||||
void rk628_mode_copy(struct rk628 *rk628, struct drm_display_mode *dst,
|
||||
const struct drm_display_mode *src);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user