From 0d8657dd3056063fb115946b10157477b5c70451 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 20 Nov 2023 09:09:45 +0000
Subject: [PATCH] enable lvds 1280x800
---
kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 254 ++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 220 insertions(+), 34 deletions(-)
diff --git a/kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index 207e314..9d6dbbf 100644
--- a/kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -59,6 +59,7 @@
PHY_STATE_DISCONNECT = 1,
PHY_STATE_CONNECT = 2,
PHY_STATE_FS_LS_ONLINE = 4,
+ PHY_STATE_SE1 = 6,
};
/**
@@ -158,6 +159,7 @@
* @utmi_ls: utmi linestate state register.
* @utmi_hstdet: utmi host disconnect register.
* @vbus_det_en: vbus detect function power down register.
+ * @port_ls_filter_con: set linestate filter time for otg port or host port.
*/
struct rockchip_usb2phy_port_cfg {
struct usb2phy_reg phy_sus;
@@ -188,6 +190,7 @@
struct usb2phy_reg utmi_ls;
struct usb2phy_reg utmi_hstdet;
struct usb2phy_reg vbus_det_en;
+ struct usb2phy_reg port_ls_filter_con;
};
/**
@@ -196,7 +199,9 @@
* @num_ports: specify how many ports that the phy has.
* @phy_tuning: phy default parameters tunning.
* @vbus_detect: vbus voltage level detection function.
- * @clkout_ctl: keep on/turn off output clk of phy.
+ * @clkout_ctl: keep on/turn off output clk of phy via commonon bit.
+ * @clkout_ctl_phy: keep on/turn off output clk of phy via phy inner
+ * debug register.
* @ls_filter_con: set linestate filter time.
* @chg_det: charger detection registers.
*/
@@ -204,8 +209,11 @@
unsigned int reg;
unsigned int num_ports;
int (*phy_tuning)(struct rockchip_usb2phy *);
- int (*vbus_detect)(struct rockchip_usb2phy *rphy, bool en);
+ int (*vbus_detect)(struct rockchip_usb2phy *rphy,
+ const struct usb2phy_reg *vbus_det_en,
+ bool en);
struct usb2phy_reg clkout_ctl;
+ struct usb2phy_reg clkout_ctl_phy;
struct usb2phy_reg ls_filter_con;
const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS];
const struct rockchip_chg_det_reg chg_det;
@@ -253,6 +261,7 @@
bool vbus_always_on;
bool vbus_enabled;
bool bypass_uart_en;
+ bool dis_u2_susphy;
int bvalid_irq;
int ls_irq;
int id_irq;
@@ -275,9 +284,10 @@
* @grf: General Register Files regmap.
* @usbgrf: USB General Register Files regmap.
* *phy_base: the base address of USB PHY.
- * @clk: clock struct of phy input clk.
+ * @clks: array of phy input clocks.
* @clk480m: clock struct of phy output clk.
* @clk_hw: clock struct of phy output clk management.
+ * @num_clks: number of phy input clocks.
* @chg_state: states involved in USB charger detection.
* @chg_type: USB charger types.
* @dcd_retries: The retry count used to track Data contact
@@ -297,9 +307,10 @@
struct regmap *grf;
struct regmap *usbgrf;
void __iomem *phy_base;
- struct clk *clk;
+ struct clk_bulk_data *clks;
struct clk *clk480m;
struct clk_hw clk480m_hw;
+ int num_clks;
enum usb_chg_state chg_state;
enum power_supply_type chg_type;
u8 dcd_retries;
@@ -344,6 +355,29 @@
return tmp == reg->enable;
}
+static inline void phy_property_enable(void __iomem *base,
+ const struct usb2phy_reg *reg, bool en)
+{
+ unsigned int val, tmp;
+
+ val = readl(base + reg->offset);
+ tmp = en ? reg->enable : reg->disable;
+ val &= ~GENMASK(reg->bitend, reg->bitstart);
+ val |= tmp << reg->bitstart;
+ writel(val, base + reg->offset);
+}
+
+static inline bool phy_property_enabled(void __iomem *base,
+ const struct usb2phy_reg *reg)
+{
+ unsigned int orig, tmp;
+ unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
+
+ orig = readl(base + reg->offset);
+ tmp = (orig & mask) >> reg->bitstart;
+ return tmp == reg->enable;
+}
+
static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)
{
struct rockchip_usb2phy *rphy =
@@ -352,7 +386,14 @@
int ret;
/* turn on 480m clk output if it is off */
- if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) {
+ if (rphy->phy_cfg->clkout_ctl_phy.enable) {
+ if (!phy_property_enabled(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy)) {
+ phy_property_enable(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy, true);
+
+ /* waiting for the clk become stable */
+ usleep_range(1200, 1300);
+ }
+ } else if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) {
ret = property_enable(base, &rphy->phy_cfg->clkout_ctl, true);
if (ret)
return ret;
@@ -371,7 +412,10 @@
struct regmap *base = get_reg_base(rphy);
/* turn off 480m clk output */
- property_enable(base, &rphy->phy_cfg->clkout_ctl, false);
+ if (rphy->phy_cfg->clkout_ctl_phy.enable)
+ phy_property_enable(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy, false);
+ else
+ property_enable(base, &rphy->phy_cfg->clkout_ctl, false);
}
static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw)
@@ -380,7 +424,10 @@
container_of(hw, struct rockchip_usb2phy, clk480m_hw);
struct regmap *base = get_reg_base(rphy);
- return property_enabled(base, &rphy->phy_cfg->clkout_ctl);
+ if (rphy->phy_cfg->clkout_ctl_phy.enable)
+ return phy_property_enabled(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy);
+ else
+ return property_enabled(base, &rphy->phy_cfg->clkout_ctl);
}
static unsigned long
@@ -410,6 +457,7 @@
{
struct device_node *node = rphy->dev->of_node;
struct clk_init_data init = {};
+ struct clk *refclk = of_clk_get_by_name(node, "phyclk");
const char *clk_name;
int ret;
@@ -420,8 +468,8 @@
/* optional override of the clockname */
of_property_read_string(node, "clock-output-names", &init.name);
- if (rphy->clk) {
- clk_name = __clk_get_name(rphy->clk);
+ if (!IS_ERR(refclk)) {
+ clk_name = __clk_get_name(refclk);
init.parent_names = &clk_name;
init.num_parents = 1;
} else {
@@ -855,7 +903,8 @@
}
if (rphy->phy_cfg->vbus_detect)
- rphy->phy_cfg->vbus_detect(rphy, vbus_det_en);
+ rphy->phy_cfg->vbus_detect(rphy, &rport->port_cfg->vbus_det_en,
+ vbus_det_en);
else
ret = property_enable(rphy->grf, &rport->port_cfg->vbus_det_en,
vbus_det_en);
@@ -1029,7 +1078,8 @@
rport->state = OTG_STATE_B_IDLE;
if (!rport->vbus_attached) {
mutex_unlock(&rport->mutex);
- rockchip_usb2phy_power_off(rport->phy);
+ if (!rport->dis_u2_susphy)
+ rockchip_usb2phy_power_off(rport->phy);
mutex_lock(&rport->mutex);
}
/* fall through */
@@ -1090,7 +1140,8 @@
rphy->chg_state = USB_CHG_STATE_UNDEFINED;
rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
mutex_unlock(&rport->mutex);
- rockchip_usb2phy_power_off(rport->phy);
+ if (!rport->dis_u2_susphy)
+ rockchip_usb2phy_power_off(rport->phy);
mutex_lock(&rport->mutex);
}
break;
@@ -1434,6 +1485,15 @@
dev_dbg(&rport->phy->dev, "FS/LS online\n");
}
break;
+ case PHY_STATE_SE1:
+ if (rport->suspended) {
+ dev_dbg(&rport->phy->dev, "linestate is SE1, power on phy\n");
+ mutex_unlock(&rport->mutex);
+ rockchip_usb2phy_power_on(rport->phy);
+ mutex_lock(&rport->mutex);
+ rport->suspended = false;
+ }
+ break;
case PHY_STATE_DISCONNECT:
if (!rport->suspended) {
dev_dbg(&rport->phy->dev, "Disconnected\n");
@@ -1764,6 +1824,11 @@
return NOTIFY_DONE;
}
+static void rockchip_otg_wake_lock_destroy(void *data)
+{
+ wake_lock_destroy((struct wake_lock *)(data));
+}
+
static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
struct rockchip_usb2phy_port *rport,
struct device_node *child_np)
@@ -1789,6 +1854,8 @@
of_property_read_bool(child_np, "rockchip,vbus-always-on");
rport->utmi_avalid =
of_property_read_bool(child_np, "rockchip,utmi-avalid");
+ rport->dis_u2_susphy =
+ of_property_read_bool(child_np, "rockchip,dis-u2-susphy");
/* enter lower power state when suspend */
rport->low_power_en =
@@ -1833,6 +1900,11 @@
property_enable(base, &rport->port_cfg->bvalid_set, false);
wake_lock_init(&rport->wakelock, WAKE_LOCK_SUSPEND, "rockchip_otg");
+ ret = devm_add_action_or_reset(rphy->dev, rockchip_otg_wake_lock_destroy,
+ &rport->wakelock);
+ if (ret)
+ return ret;
+
INIT_DELAYED_WORK(&rport->bypass_uart_work,
rockchip_usb_bypass_uart_work);
INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
@@ -1845,7 +1917,7 @@
EXTCON_USB_HOST, &rport->event_nb);
if (ret) {
dev_err(rphy->dev, "register USB HOST notifier failed\n");
- goto err;
+ return ret;
}
}
@@ -1861,10 +1933,6 @@
rport->suspended = true;
return 0;
-
-err:
- wake_lock_destroy(&rport->wakelock);
- return ret;
}
static int rockchip_usb2phy_probe(struct platform_device *pdev)
@@ -1963,13 +2031,19 @@
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
- rphy->clk = of_clk_get_by_name(np, "phyclk");
- if (!IS_ERR(rphy->clk)) {
- clk_prepare_enable(rphy->clk);
- } else {
- dev_info(&pdev->dev, "no phyclk specified\n");
- rphy->clk = NULL;
- }
+ ret = devm_clk_bulk_get_all(dev, &rphy->clks);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ /* Clocks are optional */
+ if (ret < 0)
+ rphy->num_clks = 0;
+ else
+ rphy->num_clks = ret;
+
+ ret = clk_bulk_prepare_enable(rphy->num_clks, rphy->clks);
+ if (ret)
+ return ret;
if (rphy->phy_cfg->phy_tuning) {
ret = rphy->phy_cfg->phy_tuning(rphy);
@@ -2061,10 +2135,8 @@
disable_clks:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
- if (rphy->clk) {
- clk_disable_unprepare(rphy->clk);
- clk_put(rphy->clk);
- }
+ clk_bulk_disable_unprepare(rphy->num_clks, rphy->clks);
+
return ret;
}
@@ -2305,6 +2377,43 @@
return ret;
}
+static int rk3528_usb2phy_tuning(struct rockchip_usb2phy *rphy)
+{
+ u32 reg;
+ int ret = 0;
+
+ /* Turn off otg port differential receiver in suspend mode */
+ reg = readl(rphy->phy_base + 0x30);
+ writel(reg & ~BIT(2), rphy->phy_base + 0x30);
+
+ /* Turn off host port differential receiver in suspend mode */
+ reg = readl(rphy->phy_base + 0x0430);
+ writel(reg & ~BIT(2), rphy->phy_base + 0x0430);
+
+ /* Set otg port HS eye height to 400mv(default is 450mv) */
+ reg = readl(rphy->phy_base + 0x30);
+ reg &= ~GENMASK(6, 4);
+ reg |= (0x00 << 4);
+ writel(reg, rphy->phy_base + 0x30);
+
+ /* Set host port HS eye height to 400mv(default is 450mv) */
+ reg = readl(rphy->phy_base + 0x430);
+ reg &= ~GENMASK(6, 4);
+ reg |= (0x00 << 4);
+ writel(reg, rphy->phy_base + 0x430);
+
+ /* Choose the Tx fs/ls data as linestate from TX driver for otg port */
+ reg = readl(rphy->phy_base + 0x94);
+ reg &= ~GENMASK(6, 3);
+ reg |= (0x03 << 3);
+ writel(reg, rphy->phy_base + 0x94);
+
+ /* Enable otg and host ports phy irq to pmu wakeup source */
+ ret |= regmap_write(rphy->grf, 0x80004, 0x00030003);
+
+ return ret;
+}
+
static int rk3568_usb2phy_tuning(struct rockchip_usb2phy *rphy)
{
u32 reg;
@@ -2352,18 +2461,20 @@
return ret;
}
-static int rk3568_vbus_detect_control(struct rockchip_usb2phy *rphy, bool en)
+static int rockchip_usb2phy_vbus_det_control(struct rockchip_usb2phy *rphy,
+ const struct usb2phy_reg *vbus_det_en,
+ bool en)
{
u32 reg;
if (en) {
- reg = readl(rphy->phy_base + 0x3c);
+ reg = readl(rphy->phy_base + vbus_det_en->offset);
/* Enable vbus voltage level detection function */
- writel(reg & ~BIT(7), rphy->phy_base + 0x3c);
+ writel(reg & ~BIT(7), rphy->phy_base + vbus_det_en->offset);
} else {
- reg = readl(rphy->phy_base + 0x3c);
+ reg = readl(rphy->phy_base + vbus_det_en->offset);
/* Disable vbus voltage level detection function */
- writel(reg | BIT(7), rphy->phy_base + 0x3c);
+ writel(reg | BIT(7), rphy->phy_base + vbus_det_en->offset);
}
return 0;
@@ -2397,6 +2508,14 @@
rport = &rphy->ports[index];
if (!rport->phy)
continue;
+
+ if (rport->port_cfg->port_ls_filter_con.enable) {
+ ret = regmap_write(rphy->grf,
+ rport->port_cfg->port_ls_filter_con.offset,
+ rport->port_cfg->port_ls_filter_con.enable);
+ if (ret)
+ dev_err(rphy->dev, "failed to set port ls filter %d\n", ret);
+ }
if (rport->port_id == USB2PHY_PORT_OTG &&
(rport->id_irq > 0 || rphy->irq > 0)) {
@@ -2466,6 +2585,14 @@
rport = &rphy->ports[index];
if (!rport->phy)
continue;
+
+ if (rport->port_cfg->port_ls_filter_con.disable) {
+ ret = regmap_write(rphy->grf,
+ rport->port_cfg->port_ls_filter_con.offset,
+ rport->port_cfg->port_ls_filter_con.disable);
+ if (ret)
+ dev_err(rphy->dev, "failed to set port ls filter %d\n", ret);
+ }
if (rport->port_id == USB2PHY_PORT_OTG &&
(rport->id_irq > 0 || rphy->irq > 0)) {
@@ -2988,12 +3115,69 @@
{ /* sentinel */ }
};
+static const struct rockchip_usb2phy_cfg rk3528_phy_cfgs[] = {
+ {
+ .reg = 0xffdf0000,
+ .num_ports = 2,
+ .phy_tuning = rk3528_usb2phy_tuning,
+ .vbus_detect = rockchip_usb2phy_vbus_det_control,
+ .clkout_ctl_phy = { 0x041c, 7, 2, 0, 0x27 },
+ .port_cfgs = {
+ [USB2PHY_PORT_OTG] = {
+ .phy_sus = { 0x6004c, 8, 0, 0, 0x1d1 },
+ .bvalid_det_en = { 0x60074, 2, 2, 0, 1 },
+ .bvalid_det_st = { 0x60078, 2, 2, 0, 1 },
+ .bvalid_det_clr = { 0x6007c, 2, 2, 0, 1 },
+ .bvalid_set = { 0x6004c, 15, 14, 0, 3 },
+ .iddig_output = { 0x6004c, 10, 10, 0, 1 },
+ .iddig_en = { 0x6004c, 9, 9, 0, 1 },
+ .idfall_det_en = { 0x60074, 5, 5, 0, 1 },
+ .idfall_det_st = { 0x60078, 5, 5, 0, 1 },
+ .idfall_det_clr = { 0x6007c, 5, 5, 0, 1 },
+ .idrise_det_en = { 0x60074, 4, 4, 0, 1 },
+ .idrise_det_st = { 0x60078, 4, 4, 0, 1 },
+ .idrise_det_clr = { 0x6007c, 4, 4, 0, 1 },
+ .ls_det_en = { 0x60074, 0, 0, 0, 1 },
+ .ls_det_st = { 0x60078, 0, 0, 0, 1 },
+ .ls_det_clr = { 0x6007c, 0, 0, 0, 1 },
+ .utmi_avalid = { 0x6006c, 1, 1, 0, 1 },
+ .utmi_bvalid = { 0x6006c, 0, 0, 0, 1 },
+ .utmi_iddig = { 0x6006c, 6, 6, 0, 1 },
+ .utmi_ls = { 0x6006c, 5, 4, 0, 1 },
+ .vbus_det_en = { 0x003c, 7, 7, 0, 1 },
+ .port_ls_filter_con = { 0x60080, 19, 0, 0x30100, 0x20 },
+ },
+ [USB2PHY_PORT_HOST] = {
+ .phy_sus = { 0x6005c, 8, 0, 0x1d2, 0x1d1 },
+ .ls_det_en = { 0x60090, 0, 0, 0, 1 },
+ .ls_det_st = { 0x60094, 0, 0, 0, 1 },
+ .ls_det_clr = { 0x60098, 0, 0, 0, 1 },
+ .utmi_ls = { 0x6006c, 13, 12, 0, 1 },
+ .utmi_hstdet = { 0x6006c, 15, 15, 0, 1 },
+ .port_ls_filter_con = { 0x6009c, 19, 0, 0x30100, 0x20 },
+ }
+ },
+ .chg_det = {
+ .chg_mode = { 0x6004c, 8, 0, 0, 0x1d7 },
+ .cp_det = { 0x6006c, 19, 19, 0, 1 },
+ .dcp_det = { 0x6006c, 18, 18, 0, 1 },
+ .dp_det = { 0x6006c, 20, 20, 0, 1 },
+ .idm_sink_en = { 0x60058, 1, 1, 0, 1 },
+ .idp_sink_en = { 0x60058, 0, 0, 0, 1 },
+ .idp_src_en = { 0x60058, 2, 2, 0, 1 },
+ .rdm_pdwn_en = { 0x60058, 3, 3, 0, 1 },
+ .vdm_src_en = { 0x60058, 5, 5, 0, 1 },
+ .vdp_src_en = { 0x60058, 4, 4, 0, 1 },
+ },
+ }
+};
+
static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
{
.reg = 0xfe8a0000,
.num_ports = 2,
.phy_tuning = rk3568_usb2phy_tuning,
- .vbus_detect = rk3568_vbus_detect_control,
+ .vbus_detect = rockchip_usb2phy_vbus_det_control,
.clkout_ctl = { 0x0008, 4, 4, 1, 0 },
.ls_filter_con = { 0x0040, 19, 0, 0x30100, 0x00020 },
.port_cfgs = {
@@ -3020,6 +3204,7 @@
.utmi_bvalid = { 0x00c0, 9, 9, 0, 1 },
.utmi_iddig = { 0x00c0, 6, 6, 0, 1 },
.utmi_ls = { 0x00c0, 5, 4, 0, 1 },
+ .vbus_det_en = { 0x003c, 7, 7, 0, 1 },
},
[USB2PHY_PORT_HOST] = {
/* Select suspend control from controller */
@@ -3123,6 +3308,7 @@
{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
{ .compatible = "rockchip,rk3368-usb2phy", .data = &rk3368_phy_cfgs },
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
+ { .compatible = "rockchip,rk3528-usb2phy", .data = &rk3528_phy_cfgs },
{ .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs },
{ .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs },
{}
--
Gitblit v1.6.2