From d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 02:45:28 +0000 Subject: [PATCH] add boot partition size --- kernel/drivers/phy/rockchip/phy-rockchip-typec.c | 310 ++++++++++++++++++++++++++++++++++----------------- 1 files changed, 204 insertions(+), 106 deletions(-) diff --git a/kernel/drivers/phy/rockchip/phy-rockchip-typec.c b/kernel/drivers/phy/rockchip/phy-rockchip-typec.c index 24adca0..13d849d 100644 --- a/kernel/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/kernel/drivers/phy/rockchip/phy-rockchip-typec.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd * Author: Chris Zhong <zyw@rock-chips.com> * Kever Yang <kever.yang@rock-chips.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. * * The ROCKCHIP Type-C PHY has two PLL clocks. The first PLL clock * is used for USB3, the second PLL clock is used for DP. This Type-C PHY has @@ -42,7 +34,6 @@ * This Type-C PHY driver supports normal and flip orientation. The orientation * is reported by the EXTCON_PROP_USB_TYPEC_POLARITY property: true is flip * orientation, false is normal orientation. - * */ #include <linux/clk.h> @@ -60,6 +51,8 @@ #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/reset.h> +#include <linux/usb/typec_dp.h> +#include <linux/usb/typec_mux.h> #include <linux/mfd/syscon.h> #include <linux/phy/phy.h> @@ -393,7 +386,7 @@ }; /** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. + * struct rockchip_usb3phy_port_cfg - usb3-phy port configuration. * @reg: the base address for usb3-phy config. * @typec_conn_dir: the register of type-c connector direction. * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. @@ -419,22 +412,31 @@ int pe; }; +enum { + TYPEC_PHY_USB, + TYPEC_PHY_DP, + TYPEC_PHY_MAX, +}; + struct rockchip_typec_phy { struct device *dev; void __iomem *base; - struct extcon_dev *extcon; + struct typec_mux *mux; + struct typec_switch *sw; struct regmap *grf_regs; struct clk *clk_core; struct clk *clk_ref; struct reset_control *uphy_rst; struct reset_control *pipe_rst; struct reset_control *tcphy_rst; + struct phy *phys[TYPEC_PHY_MAX]; const struct rockchip_usb3phy_port_cfg *port_cfgs; /* mutex to protect access to individual PHYs */ struct mutex lock; bool flip; u8 mode; + u8 new_mode; struct phy_config config[3][4]; }; @@ -635,7 +637,6 @@ }; enum phy_dp_power_state { - PHY_DP_POWER_STATE_DISABLED = -1, PHY_DP_POWER_STATE_A0, PHY_DP_POWER_STATE_A1, PHY_DP_POWER_STATE_A2, @@ -843,56 +844,65 @@ writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane)); } -static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) +static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, int link_rate, + u8 swing, u8 pre_emp, u32 lane) { + u16 val; + writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane)); writel(0x6799, tcphy->base + TX_PSC_A0(lane)); writel(0x6798, tcphy->base + TX_PSC_A1(lane)); writel(0x98, tcphy->base + TX_PSC_A2(lane)); writel(0x98, tcphy->base + TX_PSC_A3(lane)); + + writel(tcphy->config[swing][pre_emp].swing, + tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); + writel(tcphy->config[swing][pre_emp].pe, + tcphy->base + TX_TXCC_CPOST_MULT_00(lane)); + + if (swing == 2 && pre_emp == 0 && link_rate != 540000) { + writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane)); + writel(0x13c, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); + } else { + writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); + writel(0x0400, tcphy->base + TX_DIAG_TX_DRV(lane)); + } + + val = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); + val = val & 0x8fff; + switch (link_rate) { + case 540000: + val |= (5 << 12); + break; + case 162000: + case 270000: + default: + val |= (6 << 12); + break; + } + writel(val, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); } int tcphy_dp_set_phy_config(struct phy *phy, int link_rate, int lane_count, u8 swing, u8 pre_emp) { struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); - u8 i, j, lane; - u32 val; + u8 i; if (!phy->power_count) return -EPERM; - if (lane_count == 4) { - i = 0; - j = 3; + if (tcphy->mode == MODE_DFP_DP) { + for (i = 0; i < 4; i++) + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, i); } else { if (tcphy->flip) { - i = 0; - j = 1; + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 0); + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 1); } else { - i = 2; - j = 3; + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 2); + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 3); } - } - - for (lane = i; lane <= j; lane++) { - writel(tcphy->config[swing][pre_emp].swing, - tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); - writel(tcphy->config[swing][pre_emp].pe, - tcphy->base + TX_TXCC_CPOST_MULT_00(lane)); - - if (swing == 2 && pre_emp == 0 && link_rate != 540000) { - writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane)); - writel(0x13c, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); - } else { - writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); - writel(0x0400, tcphy->base + TX_DIAG_TX_DRV(lane)); - } - - val = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); - val &= ~GENMASK(14, 12); - val |= ((link_rate == 540000) ? 0x5 : 0x6) << 12; - writel(val, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); } return 0; @@ -1277,20 +1287,20 @@ tcphy_cfg_usb3_to_usb2_only(tcphy, true); tcphy_cfg_dp_pll(tcphy, DP_DEFAULT_RATE); for (i = 0; i < 4; i++) - tcphy_dp_cfg_lane(tcphy, i); + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, i); } else { tcphy_cfg_usb3_pll(tcphy); tcphy_cfg_dp_pll(tcphy, DP_DEFAULT_RATE); if (tcphy->flip) { tcphy_tx_usb3_cfg_lane(tcphy, 3); tcphy_rx_usb3_cfg_lane(tcphy, 2); - tcphy_dp_cfg_lane(tcphy, 0); - tcphy_dp_cfg_lane(tcphy, 1); + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 0); + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 1); } else { tcphy_tx_usb3_cfg_lane(tcphy, 0); tcphy_rx_usb3_cfg_lane(tcphy, 1); - tcphy_dp_cfg_lane(tcphy, 2); - tcphy_dp_cfg_lane(tcphy, 3); + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 2); + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 3); } } @@ -1334,50 +1344,52 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) { - struct extcon_dev *edev = tcphy->extcon; - union extcon_property_value property; - unsigned int id; - bool ufp, dp; - u8 mode; - int ret; + return tcphy->new_mode; +} - if (!edev) - return MODE_DFP_USB; +static int tcphy_orien_sw_set(struct typec_switch *sw, + enum typec_orientation orien) +{ + struct rockchip_typec_phy *tcphy = typec_switch_get_drvdata(sw); - ufp = extcon_get_state(edev, EXTCON_USB); - dp = extcon_get_state(edev, EXTCON_DISP_DP); + mutex_lock(&tcphy->lock); - mode = MODE_DFP_USB; - id = EXTCON_USB_HOST; - - if (ufp) { - mode = MODE_UFP_USB; - id = EXTCON_USB; - } else if (dp) { - mode = MODE_DFP_DP; - id = EXTCON_DISP_DP; - - ret = extcon_get_property(edev, id, EXTCON_PROP_USB_SS, - &property); - if (ret) { - dev_err(tcphy->dev, "get superspeed property failed\n"); - return ret; - } - - if (property.intval) - mode |= MODE_DFP_USB; + if (orien == TYPEC_ORIENTATION_NONE) { + tcphy->new_mode = MODE_DISCONNECT; + goto unlock_ret; } - ret = extcon_get_property(edev, id, EXTCON_PROP_USB_TYPEC_POLARITY, - &property); - if (ret) { - dev_err(tcphy->dev, "get polarity property failed\n"); - return ret; + tcphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false; + tcphy->new_mode = MODE_DFP_USB; + +unlock_ret: + mutex_unlock(&tcphy->lock); + return 0; +} + +static int tcphy_setup_orien_switch(struct rockchip_typec_phy *tcphy) +{ + struct typec_switch_desc sw_desc = { }; + + sw_desc.drvdata = tcphy; + sw_desc.fwnode = dev_fwnode(tcphy->dev); + sw_desc.set = tcphy_orien_sw_set; + + tcphy->sw = typec_switch_register(tcphy->dev, &sw_desc); + if (IS_ERR(tcphy->sw)) { + dev_err(tcphy->dev, "Error register typec orientation switch: %ld\n", + PTR_ERR(tcphy->sw)); + return PTR_ERR(tcphy->sw); } - tcphy->flip = property.intval ? 1 : 0; + return 0; +} - return mode; +static void udphy_orien_switch_unregister(void *data) +{ + struct rockchip_typec_phy *tcphy = data; + + typec_switch_unregister(tcphy->sw); } static int _rockchip_usb3_phy_power_on(struct rockchip_typec_phy *tcphy) @@ -1415,7 +1427,6 @@ regmap_read(tcphy->grf_regs, reg->offset, &val); if (!(val & BIT(reg->enable_bit))) { tcphy->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB); - /* enable usb3 host */ tcphy_cfg_usb3_to_usb2_only(tcphy, false); goto unlock_ret; @@ -1573,6 +1584,68 @@ .owner = THIS_MODULE, }; +static int tcphy_typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state) +{ + struct rockchip_typec_phy *tcphy = typec_mux_get_drvdata(mux); + struct typec_displayport_data *data; + int hpd = 0; + + mutex_lock(&tcphy->lock); + + switch (state->mode) { + case TYPEC_STATE_SAFE: + fallthrough; + case TYPEC_STATE_USB: + tcphy->new_mode = MODE_DFP_USB; + phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], 0); + break; + case TYPEC_DP_STATE_C: + case TYPEC_DP_STATE_E: + tcphy->new_mode = MODE_DFP_DP; + data = state->data; + hpd = !!(data->status & DP_STATUS_HPD_STATE); + phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 4 : 0); + break; + case TYPEC_DP_STATE_D: + tcphy->new_mode = MODE_DFP_DP | MODE_DFP_USB; + data = state->data; + hpd = !!(data->status & DP_STATUS_HPD_STATE); + phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 2 : 0); + break; + default: + break; + } + + mutex_unlock(&tcphy->lock); + + return 0; +} + +static int tcphy_setup_typec_mux(struct rockchip_typec_phy *tcphy) +{ + struct typec_mux_desc mux_desc = {}; + + mux_desc.drvdata = tcphy; + mux_desc.fwnode = dev_fwnode(tcphy->dev); + mux_desc.set = tcphy_typec_mux_set; + + tcphy->mux = typec_mux_register(tcphy->dev, &mux_desc); + if (IS_ERR(tcphy->mux)) { + dev_err(tcphy->dev, "Error register typec mux: %ld\n", + PTR_ERR(tcphy->mux)); + return PTR_ERR(tcphy->mux); + } + + return 0; +} + +static void tcphy_typec_mux_unregister(void *data) +{ + struct rockchip_typec_phy *tcphy = data; + + typec_mux_unregister(tcphy->mux); +} + static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy, struct device *dev) { @@ -1683,8 +1756,8 @@ } if (!tcphy->port_cfgs) { - dev_err(dev, "no phy-config can be matched with %s node\n", - np->name); + dev_err(dev, "no phy-config can be matched with %pOFn node\n", + np); return -EINVAL; } @@ -1693,20 +1766,30 @@ return ret; tcphy->dev = dev; + tcphy->new_mode = MODE_DFP_USB; platform_set_drvdata(pdev, tcphy); mutex_init(&tcphy->lock); typec_phy_pre_init(tcphy); - tcphy->extcon = extcon_get_edev_by_phandle(dev, 0); - if (IS_ERR(tcphy->extcon)) { - if (PTR_ERR(tcphy->extcon) == -ENODEV) { - tcphy->extcon = NULL; - } else { - if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER) - dev_err(dev, "Invalid or missing extcon\n"); - return PTR_ERR(tcphy->extcon); - } + if (device_property_present(dev, "orientation-switch")) { + ret = tcphy_setup_orien_switch(tcphy); + if (ret) + return ret; + ret = devm_add_action_or_reset(dev, udphy_orien_switch_unregister, + tcphy); + if (ret) + return ret; + } + + if (device_property_present(dev, "svid")) { + ret = tcphy_setup_typec_mux(tcphy); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, tcphy_typec_mux_unregister, tcphy); + if (ret) + return ret; } pm_runtime_enable(dev); @@ -1714,20 +1797,31 @@ for_each_available_child_of_node(np, child_np) { struct phy *phy; - if (!of_node_cmp(child_np->name, "dp-port")) + if (!of_node_cmp(child_np->name, "dp-port")) { phy = devm_phy_create(dev, child_np, &rockchip_dp_phy_ops); - else if (!of_node_cmp(child_np->name, "usb3-port")) + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy: %s\n", + child_np->name); + of_node_put(child_np); + ret = PTR_ERR(phy); + goto error; + } + tcphy->phys[TYPEC_PHY_DP] = phy; + } else if (!of_node_cmp(child_np->name, "usb3-port")) { phy = devm_phy_create(dev, child_np, &rockchip_usb3_phy_ops); - else + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy: %s\n", + child_np->name); + of_node_put(child_np); + ret = PTR_ERR(phy); + goto error; + } + tcphy->phys[TYPEC_PHY_USB] = phy; + } else { continue; - if (IS_ERR(phy)) { - dev_err(dev, "failed to create phy: %s\n", - child_np->name); - pm_runtime_disable(dev); - return PTR_ERR(phy); } phy_set_drvdata(phy, tcphy); @@ -1736,11 +1830,15 @@ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); if (IS_ERR(phy_provider)) { dev_err(dev, "Failed to register phy provider\n"); - pm_runtime_disable(dev); - return PTR_ERR(phy_provider); + ret = PTR_ERR(phy_provider); + goto error; } return 0; + +error: + pm_runtime_disable(dev); + return ret; } static int rockchip_typec_phy_remove(struct platform_device *pdev) -- Gitblit v1.6.2