* [PATCH v2 2/4] phy: rockchip-typec: support variable phy config value
From: Lin Huang @ 2018-05-09 10:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525861364-26323-1-git-send-email-hl@rock-chips.com>
the phy config values used to fix in dp firmware, but some boards
need change these values to do training and get the better eye diagram
result. So support that in phy driver.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Signed-off-by: Lin Huang <hl@rock-chips.com>
---
Changes in v2:
- update patch following Enric suggest
drivers/phy/rockchip/phy-rockchip-typec.c | 284 +++++++++++++++++++-----------
include/soc/rockchip/rockchip_phy_typec.h | 64 +++++++
2 files changed, 250 insertions(+), 98 deletions(-)
create mode 100644 include/soc/rockchip/rockchip_phy_typec.h
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index 76a4b58..86cbd6c 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -63,6 +63,7 @@
#include <linux/mfd/syscon.h>
#include <linux/phy/phy.h>
+#include <soc/rockchip/rockchip_phy_typec.h>
#define CMN_SSM_BANDGAP (0x21 << 2)
#define CMN_SSM_BIAS (0x22 << 2)
@@ -323,21 +324,29 @@
* clock 0: PLL 0 div 1
* clock 1: PLL 1 div 2
*/
-#define CLK_PLL_CONFIG 0X30
+#define CLK_PLL1_DIV1 0x20
+#define CLK_PLL1_DIV2 0x30
#define CLK_PLL_MASK 0x33
#define CMN_READY BIT(0)
+#define DP_PLL_CLOCK_ENABLE_ACK BIT(3)
#define DP_PLL_CLOCK_ENABLE BIT(2)
+#define DP_PLL_ENABLE_ACK BIT(1)
#define DP_PLL_ENABLE BIT(0)
#define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8))
#define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8))
#define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8))
+#define DP_PLL_DATA_RATE_MASK 0xff00
-#define DP_MODE_A0 BIT(4)
-#define DP_MODE_A2 BIT(6)
-#define DP_MODE_ENTER_A0 0xc101
-#define DP_MODE_ENTER_A2 0xc104
+#define DP_MODE_MASK 0xf
+#define DP_MODE_ENTER_A0 BIT(0)
+#define DP_MODE_ENTER_A2 BIT(2)
+#define DP_MODE_ENTER_A3 BIT(3)
+#define DP_MODE_A0_ACK BIT(4)
+#define DP_MODE_A2_ACK BIT(6)
+#define DP_MODE_A3_ACK BIT(7)
+#define DP_LINK_RESET_DEASSERTED BIT(8)
#define PHY_MODE_SET_TIMEOUT 100000
@@ -349,51 +358,7 @@
#define MODE_DFP_USB BIT(1)
#define MODE_DFP_DP BIT(2)
-struct usb3phy_reg {
- u32 offset;
- u32 enable_bit;
- u32 write_enable;
-};
-
-/**
- * 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.
- * @external_psm: the register of type-c phy external psm clock.
- * @pipe_status: the register of type-c phy pipe status.
- * @usb3_host_disable: the register of type-c usb3 host disable.
- * @usb3_host_port: the register of type-c usb3 host port.
- * @uphy_dp_sel: the register of type-c phy DP select control.
- */
-struct rockchip_usb3phy_port_cfg {
- unsigned int reg;
- struct usb3phy_reg typec_conn_dir;
- struct usb3phy_reg usb3tousb2_en;
- struct usb3phy_reg external_psm;
- struct usb3phy_reg pipe_status;
- struct usb3phy_reg usb3_host_disable;
- struct usb3phy_reg usb3_host_port;
- struct usb3phy_reg uphy_dp_sel;
-};
-
-struct rockchip_typec_phy {
- struct device *dev;
- void __iomem *base;
- struct extcon_dev *extcon;
- 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;
- const struct rockchip_usb3phy_port_cfg *port_cfgs;
- /* mutex to protect access to individual PHYs */
- struct mutex lock;
-
- bool flip;
- u8 mode;
-};
+#define DP_DEFAULT_RATE 162000
struct phy_reg {
u16 value;
@@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = {
{ 0x8, CMN_DIAG_PLL0_LF_PROG },
};
-struct phy_reg dp_pll_cfg[] = {
+struct phy_reg dp_pll_rbr_cfg[] = {
{ 0xf0, CMN_PLL1_VCOCAL_INIT },
{ 0x18, CMN_PLL1_VCOCAL_ITER },
{ 0x30b9, CMN_PLL1_VCOCAL_START },
- { 0x21c, CMN_PLL1_INTDIV },
+ { 0x87, CMN_PLL1_INTDIV },
{ 0, CMN_PLL1_FRACDIV },
- { 0x5, CMN_PLL1_HIGH_THR },
- { 0x35, CMN_PLL1_SS_CTRL1 },
- { 0x7f1e, CMN_PLL1_SS_CTRL2 },
+ { 0x22, CMN_PLL1_HIGH_THR },
+ { 0x8000, CMN_PLL1_SS_CTRL1 },
+ { 0, CMN_PLL1_SS_CTRL2 },
{ 0x20, CMN_PLL1_DSM_DIAG },
{ 0, CMN_PLLSM1_USER_DEF_CTRL },
{ 0, CMN_DIAG_PLL1_OVRD },
@@ -436,9 +401,52 @@ struct phy_reg dp_pll_cfg[] = {
{ 0x8, CMN_DIAG_PLL1_LF_PROG },
{ 0x100, CMN_DIAG_PLL1_PTATIS_TUNE1 },
{ 0x7, CMN_DIAG_PLL1_PTATIS_TUNE2 },
- { 0x4, CMN_DIAG_PLL1_INCLK_CTRL },
+ { 0x1, CMN_DIAG_PLL1_INCLK_CTRL },
+};
+
+struct phy_reg dp_pll_hbr_cfg[] = {
+ { 0xf0, CMN_PLL1_VCOCAL_INIT },
+ { 0x18, CMN_PLL1_VCOCAL_ITER },
+ { 0x30b4, CMN_PLL1_VCOCAL_START },
+ { 0xe1, CMN_PLL1_INTDIV },
+ { 0, CMN_PLL1_FRACDIV },
+ { 0x5, CMN_PLL1_HIGH_THR },
+ { 0x8000, CMN_PLL1_SS_CTRL1 },
+ { 0, CMN_PLL1_SS_CTRL2 },
+ { 0x20, CMN_PLL1_DSM_DIAG },
+ { 0x1000, CMN_PLLSM1_USER_DEF_CTRL },
+ { 0, CMN_DIAG_PLL1_OVRD },
+ { 0, CMN_DIAG_PLL1_FBH_OVRD },
+ { 0, CMN_DIAG_PLL1_FBL_OVRD },
+ { 0x7, CMN_DIAG_PLL1_V2I_TUNE },
+ { 0x45, CMN_DIAG_PLL1_CP_TUNE },
+ { 0x8, CMN_DIAG_PLL1_LF_PROG },
+ { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE1 },
+ { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE2 },
+ { 0x1, CMN_DIAG_PLL1_INCLK_CTRL },
};
+struct phy_reg dp_pll_hbr2_cfg[] = {
+ { 0xf0, CMN_PLL1_VCOCAL_INIT },
+ { 0x18, CMN_PLL1_VCOCAL_ITER },
+ { 0x30b4, CMN_PLL1_VCOCAL_START },
+ { 0xe1, CMN_PLL1_INTDIV },
+ { 0, CMN_PLL1_FRACDIV },
+ { 0x5, CMN_PLL1_HIGH_THR },
+ { 0x8000, CMN_PLL1_SS_CTRL1 },
+ { 0, CMN_PLL1_SS_CTRL2 },
+ { 0x20, CMN_PLL1_DSM_DIAG },
+ { 0x1000, CMN_PLLSM1_USER_DEF_CTRL },
+ { 0, CMN_DIAG_PLL1_OVRD },
+ { 0, CMN_DIAG_PLL1_FBH_OVRD },
+ { 0, CMN_DIAG_PLL1_FBL_OVRD },
+ { 0x7, CMN_DIAG_PLL1_V2I_TUNE },
+ { 0x45, CMN_DIAG_PLL1_CP_TUNE },
+ { 0x8, CMN_DIAG_PLL1_LF_PROG },
+ { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE1 },
+ { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE2 },
+ { 0x1, CMN_DIAG_PLL1_INCLK_CTRL },
+};
static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
{
.reg = 0xff7c0000,
@@ -484,7 +492,7 @@ static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy)
rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
rdata &= ~CLK_PLL_MASK;
- rdata |= CLK_PLL_CONFIG;
+ rdata |= CLK_PLL1_DIV2;
writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
}
@@ -498,17 +506,44 @@ static void tcphy_cfg_usb3_pll(struct rockchip_typec_phy *tcphy)
tcphy->base + usb3_pll_cfg[i].addr);
}
-static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
+static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy, int link_rate)
{
- u32 i;
+ struct phy_reg *phy_cfg;
+ u32 clk_ctrl;
+ u32 i, cfg_size, hsclk_sel;
+
+ hsclk_sel = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+ hsclk_sel &= ~CLK_PLL_MASK;
+
+ switch (link_rate) {
+ case 162000:
+ clk_ctrl = DP_PLL_DATA_RATE_RBR;
+ hsclk_sel |= CLK_PLL1_DIV2;
+ phy_cfg = dp_pll_rbr_cfg;
+ cfg_size = ARRAY_SIZE(dp_pll_rbr_cfg);
+ break;
+ case 270000:
+ clk_ctrl = DP_PLL_DATA_RATE_HBR;
+ hsclk_sel |= CLK_PLL1_DIV2;
+ phy_cfg = dp_pll_hbr_cfg;
+ cfg_size = ARRAY_SIZE(dp_pll_hbr_cfg);
+ break;
+ case 540000:
+ clk_ctrl = DP_PLL_DATA_RATE_HBR2;
+ hsclk_sel |= CLK_PLL1_DIV1;
+ phy_cfg = dp_pll_hbr2_cfg;
+ cfg_size = ARRAY_SIZE(dp_pll_hbr2_cfg);
+ break;
+ }
+
+ clk_ctrl |= DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE;
+ writel(clk_ctrl, tcphy->base + DP_CLK_CTL);
- /* set the default mode to RBR */
- writel(DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE | DP_PLL_DATA_RATE_RBR,
- tcphy->base + DP_CLK_CTL);
+ writel(hsclk_sel, tcphy->base + CMN_DIAG_HSCLK_SEL);
/* load the configuration of PLL1 */
- for (i = 0; i < ARRAY_SIZE(dp_pll_cfg); i++)
- writel(dp_pll_cfg[i].value, tcphy->base + dp_pll_cfg[i].addr);
+ for (i = 0; i < cfg_size; i++)
+ writel(phy_cfg[i].value, tcphy->base + phy_cfg[i].addr);
}
static void tcphy_tx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane)
@@ -535,9 +570,10 @@ static void tcphy_rx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane)
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 rdata;
+ u16 val;
writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane));
writel(0x6799, tcphy->base + TX_PSC_A0(lane));
@@ -545,25 +581,31 @@ static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane)
writel(0x98, tcphy->base + TX_PSC_A2(lane));
writel(0x98, tcphy->base + TX_PSC_A3(lane));
- writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
- writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane));
- writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane));
- writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane));
- writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane));
- writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane));
- writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane));
- writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane));
- writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane));
- writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane));
- writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane));
- writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane));
-
- writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
- writel(0x400, tcphy->base + TX_DIAG_TX_DRV(lane));
-
- rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
- rdata = (rdata & 0x8fff) | 0x6000;
- writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(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 162000:
+ case 270000:
+ val |= (6 << 12);
+ break;
+ case 540000:
+ val |= (4 << 12);
+ break;
+ }
+ writel(val, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
}
static inline int property_enable(struct rockchip_typec_phy *tcphy,
@@ -754,30 +796,33 @@ static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
tcphy_cfg_24m(tcphy);
if (mode == MODE_DFP_DP) {
- tcphy_cfg_dp_pll(tcphy);
+ 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);
writel(PIN_ASSIGN_C_E, tcphy->base + PMA_LANE_CFG);
} else {
tcphy_cfg_usb3_pll(tcphy);
- tcphy_cfg_dp_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);
}
writel(PIN_ASSIGN_D_F, tcphy->base + PMA_LANE_CFG);
}
- writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
+ val = readl(tcphy->base + DP_MODE_CTL);
+ val &= ~DP_MODE_MASK;
+ val |= DP_MODE_ENTER_A2 | DP_LINK_RESET_DEASSERTED;
+ writel(val, tcphy->base + DP_MODE_CTL);
reset_control_deassert(tcphy->uphy_rst);
@@ -990,7 +1035,7 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
property_enable(tcphy, &cfg->uphy_dp_sel, 1);
ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
- val, val & DP_MODE_A2, 1000,
+ val, val & DP_MODE_A2_ACK, 1000,
PHY_MODE_SET_TIMEOUT);
if (ret < 0) {
dev_err(tcphy->dev, "failed to wait TCPHY enter A2\n");
@@ -999,13 +1044,19 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
tcphy_dp_aux_calibration(tcphy);
- writel(DP_MODE_ENTER_A0, tcphy->base + DP_MODE_CTL);
+ /* enter A0 mode */
+ val = readl(tcphy->base + DP_MODE_CTL);
+ val &= ~DP_MODE_MASK;
+ val |= DP_MODE_ENTER_A0;
+ writel(val, tcphy->base + DP_MODE_CTL);
ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
- val, val & DP_MODE_A0, 1000,
+ val, val & DP_MODE_A0_ACK, 1000,
PHY_MODE_SET_TIMEOUT);
if (ret < 0) {
- writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
+ val &= ~DP_MODE_MASK;
+ val |= DP_MODE_ENTER_A2;
+ writel(val, tcphy->base + DP_MODE_CTL);
dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
goto power_on_finish;
}
@@ -1023,6 +1074,7 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
static int rockchip_dp_phy_power_off(struct phy *phy)
{
struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
+ u32 val;
mutex_lock(&tcphy->lock);
@@ -1031,7 +1083,10 @@ static int rockchip_dp_phy_power_off(struct phy *phy)
tcphy->mode &= ~MODE_DFP_DP;
- writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
+ val = readl(tcphy->base + DP_MODE_CTL);
+ val &= ~DP_MODE_MASK;
+ val |= DP_MODE_ENTER_A2;
+ writel(val, tcphy->base + DP_MODE_CTL);
if (tcphy->mode == MODE_DISCONNECT)
tcphy_phy_deinit(tcphy);
@@ -1047,6 +1102,30 @@ static const struct phy_ops rockchip_dp_phy_ops = {
.owner = THIS_MODULE,
};
+static int typec_dp_phy_config(struct phy *phy, int link_rate,
+ int lanes, u8 swing, u8 pre_emp)
+{
+ struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
+ u8 i;
+
+ tcphy_cfg_dp_pll(tcphy, link_rate);
+
+ 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) {
+ tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 0);
+ tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 1);
+ } else {
+ tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 2);
+ tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 3);
+ }
+ }
+
+ return 0;
+}
+
static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
struct device *dev)
{
@@ -1087,6 +1166,14 @@ static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
return PTR_ERR(tcphy->tcphy_rst);
}
+ /*
+ * check if phy_config pass from dts, if yes,
+ * need to use this phy config to do software training later
+ */
+ if (!of_property_read_u32_array(dev->of_node, "rockchip,phy_config",
+ (u32 *)tcphy->config, sizeof(tcphy->config) / sizeof(u32)))
+ tcphy->need_software_training = 1;
+
return 0;
}
@@ -1171,6 +1258,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
}
}
+ tcphy->typec_phy_config = typec_dp_phy_config;
pm_runtime_enable(dev);
for_each_available_child_of_node(np, child_np) {
diff --git a/include/soc/rockchip/rockchip_phy_typec.h b/include/soc/rockchip/rockchip_phy_typec.h
new file mode 100644
index 0000000..4a328221
--- /dev/null
+++ b/include/soc/rockchip/rockchip_phy_typec.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Lin Huang <hl@rock-chips.com>
+ */
+
+#ifndef __SOC_ROCKCHIP_PHY_TYPEC_H
+#define __SOC_ROCKCHIP_PHY_TYPEC_H
+
+struct usb3phy_reg {
+ u32 offset;
+ u32 enable_bit;
+ u32 write_enable;
+};
+
+/**
+ * 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.
+ * @external_psm: the register of type-c phy external psm clock.
+ * @pipe_status: the register of type-c phy pipe status.
+ * @usb3_host_disable: the register of type-c usb3 host disable.
+ * @usb3_host_port: the register of type-c usb3 host port.
+ * @uphy_dp_sel: the register of type-c phy DP select control.
+ */
+struct rockchip_usb3phy_port_cfg {
+ unsigned int reg;
+ struct usb3phy_reg typec_conn_dir;
+ struct usb3phy_reg usb3tousb2_en;
+ struct usb3phy_reg external_psm;
+ struct usb3phy_reg pipe_status;
+ struct usb3phy_reg usb3_host_disable;
+ struct usb3phy_reg usb3_host_port;
+ struct usb3phy_reg uphy_dp_sel;
+};
+
+struct phy_config {
+ int swing;
+ int pe;
+};
+
+struct rockchip_typec_phy {
+ struct device *dev;
+ void __iomem *base;
+ struct extcon_dev *extcon;
+ 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;
+ const struct rockchip_usb3phy_port_cfg *port_cfgs;
+ /* mutex to protect access to individual PHYs */
+ struct mutex lock;
+ struct phy_config config[3][4];
+ u8 need_software_training;
+ bool flip;
+ u8 mode;
+ int (*typec_phy_config)(struct phy *phy, int link_rate,
+ int lanes, u8 swing, u8 pre_emp);
+};
+
+#endif
--
2.7.4
^ permalink raw reply related
* [PATCH v2 1/4] drm/rockchip: add transfer function for cdn-dp
From: Lin Huang @ 2018-05-09 10:22 UTC (permalink / raw)
To: linux-arm-kernel
From: Chris Zhong <zyw@rock-chips.com>
We may support training outside firmware, so we need support
dpcd read/write to get the message or do some setting with
display.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Signed-off-by: Lin Huang <hl@rock-chips.com>
---
Changes in v2:
- update patch following Enric suggest
drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 ++++++++++++++++++++++++----
drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 +
drivers/gpu/drm/rockchip/cdn-dp-reg.c | 67 ++++++++++++++++++++++++++++++----
drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++++++-
4 files changed, 120 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index c6fbdcd..cce64c1 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count)
u8 value;
*sink_count = 0;
- ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &value, 1);
- if (ret)
+ ret = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, &value, 1);
+ if (ret < 0)
return ret;
*sink_count = DP_GET_SINK_COUNT(value);
@@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
if (!cdn_dp_check_sink_connection(dp))
return -ENODEV;
- ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd,
- DP_RECEIVER_CAP_SIZE);
- if (ret) {
+ ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd,
+ sizeof(dp->dpcd));
+ if (ret < 0) {
DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret);
return ret;
}
@@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
if (!port || !dp->link.rate || !dp->link.num_lanes)
return false;
- if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status,
- DP_LINK_STATUS_SIZE)) {
+ if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) !=
+ DP_LINK_STATUS_SIZE) {
DRM_ERROR("Failed to get link status\n");
return false;
}
@@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb,
return NOTIFY_DONE;
}
+static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux,
+ struct drm_dp_aux_msg *msg)
+{
+ struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux);
+ int ret;
+ u8 status;
+
+ switch (msg->request & ~DP_AUX_I2C_MOT) {
+ case DP_AUX_NATIVE_WRITE:
+ case DP_AUX_I2C_WRITE:
+ case DP_AUX_I2C_WRITE_STATUS_UPDATE:
+ ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer,
+ msg->size);
+ break;
+ case DP_AUX_NATIVE_READ:
+ case DP_AUX_I2C_READ:
+ ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer,
+ msg->size);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ status = cdn_dp_get_aux_status(dp);
+ if (status == AUX_STATUS_ACK)
+ msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+ else if (status == AUX_STATUS_NACK)
+ msg->reply = DP_AUX_NATIVE_REPLY_NACK;
+ else if (status == AUX_STATUS_DEFER)
+ msg->reply = DP_AUX_NATIVE_REPLY_DEFER;
+
+ return ret;
+}
+
static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
{
struct cdn_dp_device *dp = dev_get_drvdata(dev);
@@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
dp->active = false;
dp->active_port = -1;
dp->fw_loaded = false;
+ dp->aux.name = "DP-AUX";
+ dp->aux.transfer = cdn_dp_aux_transfer;
+ dp->aux.dev = dev;
+
+ ret = drm_dp_aux_register(&dp->aux);
+ if (ret)
+ return ret;
INIT_WORK(&dp->event_work, cdn_dp_pd_event_work);
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index f57e296..46159b2 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -78,6 +78,7 @@ struct cdn_dp_device {
struct platform_device *audio_pdev;
struct work_struct event_work;
struct edid *edid;
+ struct drm_dp_aux aux;
struct mutex lock;
bool connected;
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
index eb3042c..afdfda0 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
@@ -221,7 +221,11 @@ static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr,
sizeof(field), field);
}
-int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
+/*
+ * Returns the number of bytes transferred on success, or a negative error
+ * code on failure. -ETIMEDOUT is returned if mailbox message not send success;
+ */
+ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
{
u8 msg[5], reg[5];
int ret;
@@ -247,24 +251,40 @@ int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
goto err_dpcd_read;
ret = cdn_dp_mailbox_read_receive(dp, data, len);
+ if (!ret)
+ return len;
err_dpcd_read:
+ DRM_DEV_ERROR(dp->dev, "dpcd read failed: %d\n", ret);
return ret;
}
-int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
+#define CDN_AUX_HEADER_SIZE 5
+#define CDN_AUX_MSG_SIZE 20
+/*
+ * Returns the number of bytes transferred on success, or a negative error
+ * code on failure. -ETIMEDOUT is returned if mailbox message not send success;
+ * -EINVAL is return if get the wrong data size after message send.
+ */
+ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
{
- u8 msg[6], reg[5];
+ u8 msg[CDN_AUX_MSG_SIZE + CDN_AUX_HEADER_SIZE];
+ u8 reg[CDN_AUX_HEADER_SIZE];
int ret;
- msg[0] = 0;
- msg[1] = 1;
+ if (WARN_ON(len > CDN_AUX_MSG_SIZE) || WARN_ON(len <= 0))
+ return -EINVAL;
+
+ msg[0] = (len >> 8) & 0xff;
+ msg[1] = len & 0xff;
msg[2] = (addr >> 16) & 0xff;
msg[3] = (addr >> 8) & 0xff;
msg[4] = addr & 0xff;
- msg[5] = value;
+
+ memcpy(msg + CDN_AUX_HEADER_SIZE, data, len);
+
ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD,
- sizeof(msg), msg);
+ CDN_AUX_HEADER_SIZE + len, msg);
if (ret)
goto err_dpcd_write;
@@ -277,8 +297,12 @@ int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
if (ret)
goto err_dpcd_write;
- if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4]))
+ if ((len != (reg[0] << 8 | reg[1])) ||
+ (addr != (reg[2] << 16 | reg[3] << 8 | reg[4]))) {
ret = -EINVAL;
+ } else {
+ return len;
+ }
err_dpcd_write:
if (ret)
@@ -286,6 +310,33 @@ int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
return ret;
}
+int cdn_dp_get_aux_status(struct cdn_dp_device *dp)
+{
+ u8 status;
+ int ret;
+
+ ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX,
+ DPTX_GET_LAST_AUX_STAUS, 0, NULL);
+ if (ret)
+ goto err_get_hpd;
+
+ ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
+ DPTX_GET_LAST_AUX_STAUS,
+ sizeof(status));
+ if (ret)
+ goto err_get_hpd;
+
+ ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status));
+ if (ret)
+ goto err_get_hpd;
+
+ return status;
+
+err_get_hpd:
+ DRM_DEV_ERROR(dp->dev, "get aux status failed: %d\n", ret);
+ return ret;
+}
+
int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
u32 i_size, const u32 *d_mem, u32 d_size)
{
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
index c4bbb4a83..6580b11 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
@@ -328,6 +328,13 @@
#define GENERAL_BUS_SETTINGS 0x03
#define GENERAL_TEST_ACCESS 0x04
+/* AUX status*/
+#define AUX_STATUS_ACK 0
+#define AUX_STATUS_NACK 1
+#define AUX_STATUS_DEFER 2
+#define AUX_STATUS_SINK_ERROR 3
+#define AUX_STATUS_BUS_ERROR 4
+
#define DPTX_SET_POWER_MNG 0x00
#define DPTX_SET_HOST_CAPABILITIES 0x01
#define DPTX_GET_EDID 0x02
@@ -469,8 +476,11 @@ int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip);
int cdn_dp_event_config(struct cdn_dp_device *dp);
u32 cdn_dp_get_event(struct cdn_dp_device *dp);
int cdn_dp_get_hpd_status(struct cdn_dp_device *dp);
-int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value);
-int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len);
+ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr,
+ u8 *data, u16 len);
+ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr,
+ u8 *data, u16 len);
+int cdn_dp_get_aux_status(struct cdn_dp_device *dp);
int cdn_dp_get_edid_block(void *dp, u8 *edid,
unsigned int block, size_t length);
int cdn_dp_train_link(struct cdn_dp_device *dp);
--
2.7.4
^ permalink raw reply related
* [PATCH V2 05/11] PM / Domains: Allow a better error handling of dev_pm_domain_attach()
From: Ulf Hansson @ 2018-05-09 10:17 UTC (permalink / raw)
To: linux-arm-kernel
The callers of dev_pm_domain_attach() currently checks the returned error
code for -EPROBE_DEFER and needs to ignore other error codes. This is an
unnecessary limitation, which also leads to a rather strange behaviour in
the error path.
Address this limitation, by changing the return codes from
acpi_dev_pm_attach() and genpd_dev_pm_attach(). More precisely, let them
return 0, when no PM domain is needed for the device and then return 1, in
case the device was successfully attached to its PM domain. In this way,
dev_pm_domain_attach(), gets a better understanding of what happens in the
attach attempts and also allowing its caller to better act on real errors
codes.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
Changes in v2:
- Return 0 from the inline variant of dev_pm_domain_attach(), to make
sure probing still works when CONFIG_PM is unset.
---
drivers/acpi/device_pm.c | 6 +++---
drivers/base/power/common.c | 7 ++++---
drivers/base/power/domain.c | 19 ++++++++++---------
include/linux/acpi.h | 2 +-
include/linux/pm_domain.h | 4 ++--
5 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index d006300..a7c2673 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -1257,7 +1257,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
struct acpi_device *adev = ACPI_COMPANION(dev);
if (!adev)
- return -ENODEV;
+ return 0;
/*
* Only attach the power domain to the first device if the
@@ -1265,7 +1265,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
* management twice.
*/
if (!acpi_device_is_first_physical_node(adev, dev))
- return -EBUSY;
+ return 0;
acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func);
dev_pm_domain_set(dev, &acpi_general_pm_domain);
@@ -1275,7 +1275,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
}
dev->pm_domain->detach = acpi_dev_pm_detach;
- return 0;
+ return 1;
}
EXPORT_SYMBOL_GPL(acpi_dev_pm_attach);
#endif /* CONFIG_PM */
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
index f3cf61f..5e4b481 100644
--- a/drivers/base/power/common.c
+++ b/drivers/base/power/common.c
@@ -98,7 +98,8 @@ EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data);
* Callers must ensure proper synchronization of this function with power
* management callbacks.
*
- * Returns 0 on successfully attached PM domain or negative error code.
+ * Returns 0 on successfully attached PM domain and when it found that the
+ * device don't need a PM domain, else a negative error code.
*/
int dev_pm_domain_attach(struct device *dev, bool power_on)
{
@@ -108,10 +109,10 @@ int dev_pm_domain_attach(struct device *dev, bool power_on)
return -EEXIST;
ret = acpi_dev_pm_attach(dev, power_on);
- if (ret)
+ if (!ret)
ret = genpd_dev_pm_attach(dev);
- return ret;
+ return ret < 0 ? ret : 0;
}
EXPORT_SYMBOL_GPL(dev_pm_domain_attach);
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index b816adb..455ecea 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -2180,10 +2180,11 @@ static void genpd_dev_pm_sync(struct device *dev)
* Parse device's OF node to find a PM domain specifier. If such is found,
* attaches the device to retrieved pm_domain ops.
*
- * Returns 0 on successfully attached PM domain or negative error code. Note
- * that if a power-domain exists for the device, but it cannot be found or
- * turned on, then return -EPROBE_DEFER to ensure that the device is not
- * probed and to re-try again later.
+ * Returns 1 on successfully attached PM domain, 0 when the device don't need a
+ * PM domain or a negative error code in case of failures. Note that if a
+ * power-domain exists for the device, but it cannot be found or turned on,
+ * then return -EPROBE_DEFER to ensure that the device is not probed and to
+ * re-try again later.
*/
int genpd_dev_pm_attach(struct device *dev)
{
@@ -2192,12 +2193,12 @@ int genpd_dev_pm_attach(struct device *dev)
int ret;
if (!dev->of_node)
- return -ENODEV;
+ return 0;
ret = of_parse_phandle_with_args(dev->of_node, "power-domains",
"#power-domain-cells", 0, &pd_args);
if (ret < 0)
- return ret;
+ return 0;
mutex_lock(&gpd_list_lock);
pd = genpd_get_from_provider(&pd_args);
@@ -2218,7 +2219,7 @@ int genpd_dev_pm_attach(struct device *dev)
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to add to PM domain %s: %d",
pd->name, ret);
- goto out;
+ return ret;
}
dev->pm_domain->detach = genpd_dev_pm_detach;
@@ -2230,8 +2231,8 @@ int genpd_dev_pm_attach(struct device *dev)
if (ret)
genpd_remove_device(pd, dev);
-out:
- return ret ? -EPROBE_DEFER : 0;
+
+ return ret ? -EPROBE_DEFER : 1;
}
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 15bfb15..c01675b 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -899,7 +899,7 @@ static inline int acpi_subsys_runtime_suspend(struct device *dev) { return 0; }
static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; }
static inline int acpi_dev_pm_attach(struct device *dev, bool power_on)
{
- return -ENODEV;
+ return 0;
}
#endif
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 04dbef9..ab18548 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -280,7 +280,7 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn,
static inline int genpd_dev_pm_attach(struct device *dev)
{
- return -ENODEV;
+ return 0;
}
static inline
@@ -297,7 +297,7 @@ extern void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd);
#else
static inline int dev_pm_domain_attach(struct device *dev, bool power_on)
{
- return -ENODEV;
+ return 0;
}
static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {}
static inline void dev_pm_domain_set(struct device *dev,
--
2.7.4
^ permalink raw reply related
* [PATCH v7 16/24] ASoC: qdsp6: q6asm: Add support to audio stream apis
From: Banajit Goswami @ 2018-05-09 10:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180501120820.11016-17-srinivas.kandagatla@linaro.org>
On 5/1/2018 5:08 AM, Srinivas Kandagatla wrote:
> This patch adds support to open, write and media format commands
> in the q6asm module.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Reviewed-and-tested-by: Rohit kumar <rohitkr@codeaurora.org>
> ---
> sound/soc/qcom/qdsp6/q6asm.c | 839 ++++++++++++++++++++++++++++++++++++++++++-
> sound/soc/qcom/qdsp6/q6asm.h | 49 +++
> 2 files changed, 887 insertions(+), 1 deletion(-)
>
> diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
> index 5a573e927a5e..a3073de235e1 100644
> --- a/sound/soc/qcom/qdsp6/q6asm.c
> +++ b/sound/soc/qcom/qdsp6/q6asm.c
> @@ -10,6 +10,8 @@
<snip>
> EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
>
> +static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
> +{
> + struct apr_hdr *hdr = &pkt->hdr;
> + int rc;
> +
> + mutex_lock(&ac->lock);
> + ac->result.opcode = 0;
> + ac->result.status = 0;
> +
> + rc = apr_send_pkt(ac->adev, pkt);
> + if (rc < 0)
> + goto err;
> +
> + rc = wait_event_timeout(ac->cmd_wait,
> + (ac->result.opcode == hdr->opcode), 5 * HZ);
> + if (!rc) {
> + dev_err(ac->dev, "CMD timeout\n");
> + rc = -ETIMEDOUT;
> + goto err;
> + }
else set rc to 0 to avoid returning >0 value.
LGTM otherwise.
Acked-by: Banajit Goswami <bgoswami@codeaurora.org>
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH v7 23/24] ASoC: qcom: apq8096: Add db820c machine driver
From: Srinivas Kandagatla @ 2018-05-09 10:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <c52fc35d-95a6-6675-6c6e-32a0d5f486d4@codeaurora.org>
Thanks for the review Banajit.
On 09/05/18 10:15, Banajit Goswami wrote:
>
> On 5/1/2018 5:08 AM, Srinivas Kandagatla wrote:
>> This patch adds support to DB820c machine driver.
>>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> ---
>> sound/soc/qcom/Kconfig | 9 ++
>> sound/soc/qcom/Makefile | 2 +
>> sound/soc/qcom/apq8096.c | 238
>> +++++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 249 insertions(+)
>> + link = card->dai_link;
>> +
>> + for_each_child_of_node(node, np) {
>> + cpu = of_get_child_by_name(np, "cpu");
>> + platform = of_get_child_by_name(np, "platform");
>> + codec = of_get_child_by_name(np, "codec");
>> +
>> + if (!cpu) {
>> + dev_err(dev, "Can't find cpu DT node\n");
> clean up missing to kfree(card->dai_link)?
Yep, I will fix error path in next version.
>
>> + return -EINVAL;
>> + }
>> +
>> + return ret;
>> + }
>> + link->no_pcm = 1;
>> + link->ignore_suspend = 1;
> ignore_suspend will also need to be set for FE DAIs?
>
Okay!
>> + link->ignore_pmdown_time = 1;
>> + link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
>> + } else {
>> + link->platform_of_node = link->cpu_of_node;
>> + link->codec_dai_name = "snd-soc-dummy-dai";
>> + link->codec_name = "snd-soc-dummy";
>> + link->dynamic = 1;
>> + }
>> +
>> +
>> +static void apq8096_unbind(struct device *dev)
>> +{
>> + struct snd_soc_card *card = dev_get_drvdata(dev);
>> +
>> + component_unbind_all(dev, card);
>> + snd_soc_unregister_card(card);
> Should sound card not be unregistered first, before calling
> component_unbind_all()?
Yep, I will give that a go.
thanks,
srini
>
^ permalink raw reply
* [PATCH v6 07/15] KVM: arm64: Optimise FPSIMD handling to reduce guest/host thrashing
From: Dave Martin @ 2018-05-09 10:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5010b106-4aa3-fb19-bbac-55cf261f9d30@arm.com>
On Wed, May 09, 2018 at 10:46:11AM +0100, Marc Zyngier wrote:
> On 09/05/18 10:17, Dave Martin wrote:
> > On Wed, May 09, 2018 at 09:24:36AM +0100, Marc Zyngier wrote:
> >> On 08/05/18 17:44, Dave Martin wrote:
> >>> This patch refactors KVM to align the host and guest FPSIMD
> >>> save/restore logic with each other for arm64. This reduces the
> >
> > [...]
> >
> >>> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> >>> index 9699c13..6429eb6 100644
> >>> --- a/arch/arm64/include/asm/kvm_asm.h
> >>> +++ b/arch/arm64/include/asm/kvm_asm.h
> >>> @@ -33,6 +33,8 @@
> >>> /* vcpu_arch flags field values: */
> >>> #define KVM_ARM64_DEBUG_DIRTY_SHIFT 0
> >>> #define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
> >>
> >> At some point, we could remove KVM_ARM64_DEBUG_DIRTY_SHIFT as it is not
> >> used anymore (since 1ea66d27e7b0). Do not respin on this account though.
> >
> > I wondered about this... I presume this was used from assembly once
> > upon a time.
> >
> > Since I need to repost for something else anyway, shall I delete that
> > and move the defines to kvm_host.h? There's no longer an obvious reason
> > for them to be in a different header.
>
> Yes, please.
OK, will do.
> >>> diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
[...]
> >>> +void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
> >>> +{
> >>> + BUG_ON(system_supports_sve());
> >>> + BUG_ON(!current->mm);
> >>> +
> >>> + vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED | KVM_ARM64_HOST_SVE_IN_USE);
> >>> + if (test_thread_flag(TIF_SVE))
> >>> + vcpu->arch.flags |= KVM_ARM64_HOST_SVE_IN_USE;
> >>> +
> >>> + vcpu->arch.host_fpsimd_state =
> >>> + kern_hyp_va(¤t->thread.uw.fpsimd_state);
> >>
> >> ... what is the purpose of this assignment? I don't think it is harmful
> >> in any way, but I'm just wondering if I'm missing in the actual flow.
> >
> > The pointer will be NULLed by __hyp_switch_fpsimd() when loading the
> > guest state in, to indicate that there is no longer any host state to
> > save. Perhaps it would have been clearer to have a separate flag to
> > represent this change of state.
> >
> > As things stand I think you're right: the assignments are redundant.
> > We certainly need the pointer to reflect the current task, which is
> > the motivation for doing it here -- but in fact we need to do it
> > more often, at every vcpu_load().
> >
> > I think the most appropriate thing is to delete the assignment from
> > _map_fp().
> >
> > The alternative would be to add a flag for the "no host state to save"
> > case, and fpsimd_host_state only in the pid_change hook.
>
> I think I'd prefer the latter. It makes the whole pointer stuff a lot
> easier to understand (the linkages are basically static), and using
> flags is consistent with the way the rest of the kernel works. I'm not
> sure whether we need to add a new flag or simply rely on the existing
> thread flag, but that for you to decide.
OK, agreed. It should definitely help clarity.
[...]
> > Happy to keep your Reviewed-by with the discussed changes?
> Yes, no problem. I'll eyeball the changes and let you know if I spot
> anything.
OK, thanks.
I'll note the changes under the tearoff.
Cheers
---Dave
^ permalink raw reply
* [RFC PATCH] driver core: make deferring probe forever optional
From: Alexander Graf @ 2018-05-09 9:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507223438.GB14924@minitux>
On 05/08/2018 12:34 AM, Bjorn Andersson wrote:
> On Mon 07 May 12:55 PDT 2018, Rob Herring wrote:
>
>> On Mon, May 7, 2018 at 1:31 PM, Bjorn Andersson
>> <bjorn.andersson@linaro.org> wrote:
>>> On Tue 01 May 14:31 PDT 2018, Rob Herring wrote:
>>>
>>>> Deferred probe will currently wait forever on dependent devices to probe,
>>>> but sometimes a driver will never exist. It's also not always critical for
>>>> a driver to exist. Platforms can rely on default configuration from the
>>>> bootloader or reset defaults for things such as pinctrl and power domains.
>>> But how do you know if this is the case?
>> Because the platform worked before adding the dependency in the dts.
>>
> I'm worried about how to write dts files and drivers to support all
> permutation of forward and backward dependencies. And you most
> definitely have the same case with bootloader-enabled clocks,
> regulators and interconnects.
>
>>>> This is often the case with initial platform support until various drivers
>>>> get enabled.
>>> Can you please name platform that has enough support for Alexander to
>>> care about backwards and forwards compatibility but lacks a pinctrl
>>> driver.
>> Alex will have to answer that. I do agree pinctrl drivers shouldn't be
>> that hard because it is all just translating a bunch of pin data into
>> one-time (mostly) register writes, so it shouldn't take that long to
>> implement support. OTOH, maybe a pinctrl driver is low priority
>> because nothing needs it yet. Either a given board works with the
>> defaults and only some new board needs to change things or you don't
>> need pinctrl until low power modes are implemented. However, power
>> domains have the same problem and it can take years for those to get
>> proper support.
>>
>> Alex proposed declaring dts files stable and then enforcing
>> compatibility after that point. If anyone believes that will work,
>> then please send a patch marking all the platforms in the kernel tree
>> that are stable.
>>
> That might be a reasonable idea, but at least in our corner the current
> decision that devicetree should be backwards compatible does make it
> quite cumbersome to break this assumption - and in the cases we have had
> to do it it's really been necessary.
I'm sure Rob would be happy to get a list of every one of those
instances so we can see how to solve them going forward.
To give you some background: The whole discussion started with a
proposal from me to support embedded (maybe dtc aided) overlays. Some
way to have a single dtb that only enables new features such as pinctrl
when the kernel indicates support for them.
I think eventually we will have to have a mechanism like that for
platforms that want to maintain compatibility. But the less we have to
solve using it the better off everyone is, because it just increases
complexity.
>
>>>> There's at least 2 scenarios where deferred probe can render
>>>> a platform broken. Both involve using a DT which has more devices and
>>>> dependencies than the kernel supports. The 1st case is a driver may be
>>>> disabled in the kernel config.
>>> I agree that there is a chance that you _might_ get some parts of the
>>> system working by relying on the boot loader configuration, but
>>> misconfiguration issues applies to any other fundamental providers, such
>>> as clocks, regulators, power domains and gpios as well.
>> If it is only a chance, then perhaps we shouldn't allow things
>> upstream without proper drivers for all these things. That will only
>> give users the wrong impression.
>>
> It's not as much the drivers that's the problem here as it is the
> composition of the drivers. For this particular case it would be
> convenient not to ship the partial dtb, or at least not ship it with the
> promise that it's stable.
Yes, we of course need a gatekeeping event. Not every DT is in a state
where you can promise compatibility.
However, if you want to have a stable OS interface so that slow moving
Linux distribtions work well with the platform and non-Linux OSs jump on
the platform, you will have to provide some guarantees. And people just
need to be aware that they either give the guarantees or they don't get
their benefits :).
>
>>>> The 2nd case is the kernel version may
>>>> simply not have the dependent driver. This can happen if using a newer DT
>>>> (provided by firmware perhaps) with a stable kernel version.
>>>>
>>> As above, this is in no way limited to pinctrl drivers.
>> Yes, I wasn't trying to imply that with this patch. I was just
>> starting with 1 example. IOMMUs (which essentially is already doing
>> what this patch does) and power domains are the main other 2.
> qcom,iommu-v1 is bool, but depends on e.g. CONFIG_MSM_GCC_8916 which is
> tristate. So you would need to s/tristate/bool/ everything in
> drivers/clk/qcom/Kconfig as well. Not to mention that there are
> interconnects and power domains actually involved here as well...
>
>> Clocks is an obvious one too, but from the discussion I referenced
>> that problem is a bit different as platforms change from dummy
>> fixed-clocks to a real clock controller driver. That will need a
>> different solution.
> So how are you going to deal with the case when a vendor decides to ship
> their firmware package with all clocks enabled and only fixed clocks
> described in DT and as they upstream a clock driver and patch their
> firmware to do the right thing?
That is the ZynqMP case. I think this really needs to be solved using
embedded overlays, but Rob might have additional ideas :).
> (Or the much less extreme case where this happens for a single clock,
> regulator, pinctrl, interconnect, etc to fix some bug/power management
> behavior)
>
> And is this really a problem that does not exists in the ACPI world?
>
>>>> Unfortunately, this change breaks with modules as we have no way of
>>>> knowing when modules are done loading. One possibility is to make this
>>>> opt in or out based on compatible strings rather than at a subsystem level.
>>>> Ideally this information could be extracted automatically somehow. OTOH,
>>>> maybe the lists are pretty small. There's only a handful of subsystems
>>>> that can be optional, and then only so many drivers in those that can be
>>>> modules (at least for pinctrl, many drivers are built-in only).
>>>>
>>> On the Qualcomm platform most drivers are tristate and on most platforms
>>> there are size restrictions in the proprietary boot loader preventing us
>>> from boot the kernel after switching all these frameworks from tristate
>>> to bool (which feels like a more appropriate solution than your hack).
>> BTW, QCom platforms are almost the only ones with pinctrl drivers as
>> modules. They are also happen to be PIA to configure correctly for a
>> board.
>>
> There are a few pinctrl drivers for chips sitting on i2c busses, as such
> changing this requirement would trickle down to a number of possible i2c
> masters as well.
>
> Sorry to hear that you find it so difficult to configure the pinctrl,
> it's (almost) entirely using the common pinctrl bindings. Perhaps we
> need to add some documentation of the hardware in the binding?
>
>> However, I would like a solution that works with modules. It would be
>> nice to know when userspace finished processing all the coldplug
>> uevents. That would be sufficient to support modules. I researched
>> that a bit and it doesn't seem the kernel can tell when that has
>> happened.
>>
> It's not that far from the issue I have in remoteproc, where I would
> like to boot a DSP as soon as the firmware is available - which might be
> probed at any time after boot.
>
> [..]
>>>> I tested this on a RPi3 B with the pinctrl driver forced off. With this
>>>> change, the MMC/SD and UART drivers can function without the pinctrl
>>>> driver.
>>>>
>>> Cool, so what about graphics, audio, networking, usb and all the other
>>> things that people actually expect when they _use_ a distro?
>> I often care about none of those things. When I do, I'd rather boot to
>> a working console with those broken than have to debug why the kernel
>> panicked.
>>
> But that's developer-you speaking, developer-me totally agree.
>
> But when I take the role of being a user of a distro I most definitely
> do expect functionality beyond the basics used by the boot loader (UART
> and dependencies of the primary storage device).
>
> My argument is simply that in neither of these cases this patch is
> helpful.
The patch allows firmware to provide pinctrl information but maintain
backwards compatibility with kernels that don't implement pinctrl
setting. It's useful to solve that part of the transition of the DT to
enable new functionality. If you now add a device that explicitly needs
pinctrl configuration to work, that would probably need to get added
using the overlay mechanism I described above.
Alex
^ permalink raw reply
* [PATCH v7 21/24] ASoC: qdsp6: q6asm: Add q6asm dai driver
From: Banajit Goswami @ 2018-05-09 9:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180501120820.11016-22-srinivas.kandagatla@linaro.org>
On 5/1/2018 5:08 AM, Srinivas Kandagatla wrote:
> This patch adds support to q6asm dai driver which configures Q6ASM streams
> to pass pcm data.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Reviewed-and-tested-by: Rohit kumar <rohitkr@codeaurora.org>
> ---
> sound/soc/qcom/Kconfig | 4 +
> sound/soc/qcom/qdsp6/Makefile | 1 +
> sound/soc/qcom/qdsp6/q6asm-dai.c | 628 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 633 insertions(+)
> create mode 100644 sound/soc/qcom/qdsp6/q6asm-dai.c
>
Acked-by: Banajit Goswami <bgoswami@codeaurora.org>
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Applied "regulator: add binding for the SY8106A voltage regulator" to the regulator tree
From: Mark Brown @ 2018-05-09 9:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180423144657.63264-2-icenowy@aosc.io>
The patch
regulator: add binding for the SY8106A voltage regulator
has been applied to the regulator tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 32aba834f2a9fe126ff5e624371113ac1defa06e Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 7 May 2018 20:29:40 +0800
Subject: [PATCH] regulator: add binding for the SY8106A voltage regulator
SY8106A is an I2C-controlled adjustable voltage regulator made by
Silergy Corp.
Add its device tree binding.
Signed-off-by: Ondrej Jirman <megous@megous.com>
[Icenowy: Change commit message and slight fixes]
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
.../bindings/regulator/sy8106a-regulator.txt | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
diff --git a/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
new file mode 100644
index 000000000000..39a8ca73f572
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
@@ -0,0 +1,23 @@
+SY8106A Voltage regulator
+
+Required properties:
+- compatible: Must be "silergy,sy8106a"
+- reg: I2C slave address - must be <0x65>
+- silergy,fixed-microvolt - the voltage when I2C regulating is disabled (set
+ by external resistor like a fixed voltage)
+
+Any property defined as part of the core regulator binding, defined in
+./regulator.txt, can also be used.
+
+Example:
+
+ sy8106a {
+ compatible = "silergy,sy8106a";
+ reg = <0x65>;
+ regulator-name = "sy8106a-vdd";
+ silergy,fixed-microvolt = <1200000>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
--
2.17.0
^ permalink raw reply related
* Applied "regulator: add support for SY8106A regulator" to the regulator tree
From: Mark Brown @ 2018-05-09 9:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507122942.25758-3-icenowy@aosc.io>
The patch
regulator: add support for SY8106A regulator
has been applied to the regulator tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 8878302ebbc580d64f390c0acc509e5e8276598c Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 7 May 2018 20:29:41 +0800
Subject: [PATCH] regulator: add support for SY8106A regulator
SY8106A is an I2C attached single output regulator made by Silergy Corp,
which is used on several Allwinner H3/H5 SBCs to control the power
supply of the ARM cores.
Add a driver for it.
Signed-off-by: Ondrej Jirman <megous@megous.com>
[Icenowy: Change commit message, remove enable/disable code, add default
ramp_delay, add comment for go bit, add code for fixed mode voltage]
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
MAINTAINERS | 6 +
drivers/regulator/Kconfig | 7 ++
drivers/regulator/Makefile | 2 +-
drivers/regulator/sy8106a-regulator.c | 167 ++++++++++++++++++++++++++
4 files changed, 181 insertions(+), 1 deletion(-)
create mode 100644 drivers/regulator/sy8106a-regulator.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 0a1410d5a621..971300930067 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13461,6 +13461,12 @@ S: Supported
F: net/switchdev/
F: include/net/switchdev.h
+SY8106A REGULATOR DRIVER
+M: Icenowy Zheng <icenowy@aosc.io>
+S: Maintained
+F: drivers/regulator/sy8106a-regulator.c
+F: Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
+
SYNC FILE FRAMEWORK
M: Sumit Semwal <sumit.semwal@linaro.org>
R: Gustavo Padovan <gustavo@padovan.org>
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 097f61784a7d..4efae3b7e746 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -801,6 +801,13 @@ config REGULATOR_STW481X_VMMC
This driver supports the internal VMMC regulator in the STw481x
PMIC chips.
+config REGULATOR_SY8106A
+ tristate "Silergy SY8106A regulator"
+ depends on I2C && (OF || COMPILE_TEST)
+ select REGMAP_I2C
+ help
+ This driver supports SY8106A single output regulator.
+
config REGULATOR_TPS51632
tristate "TI TPS51632 Power Regulator"
depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 590674fbecd7..d81fb02bd6e9 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -100,6 +100,7 @@ obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
+obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
@@ -125,5 +126,4 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
-
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c
new file mode 100644
index 000000000000..65fbd1f0b612
--- /dev/null
+++ b/drivers/regulator/sy8106a-regulator.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// sy8106a-regulator.c - Regulator device driver for SY8106A
+//
+// Copyright (C) 2016 Ond??ej Jirman <megous@megous.com>
+// Copyright (c) 2017-2018 Icenowy Zheng <icenowy@aosc.io>
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SY8106A_REG_VOUT1_SEL 0x01
+#define SY8106A_REG_VOUT_COM 0x02
+#define SY8106A_REG_VOUT1_SEL_MASK 0x7f
+#define SY8106A_DISABLE_REG BIT(0)
+/*
+ * The I2C controlled voltage will only work when this bit is set; otherwise
+ * it will behave like a fixed regulator.
+ */
+#define SY8106A_GO_BIT BIT(7)
+
+struct sy8106a {
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ u32 fixed_voltage;
+};
+
+static const struct regmap_config sy8106a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static const struct regulator_ops sy8106a_ops = {
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ /* Enabling/disabling the regulator is not yet implemented */
+};
+
+/* Default limits measured in millivolts */
+#define SY8106A_MIN_MV 680
+#define SY8106A_MAX_MV 1950
+#define SY8106A_STEP_MV 10
+
+static const struct regulator_desc sy8106a_reg = {
+ .name = "SY8106A",
+ .id = 0,
+ .ops = &sy8106a_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1,
+ .min_uV = (SY8106A_MIN_MV * 1000),
+ .uV_step = (SY8106A_STEP_MV * 1000),
+ .vsel_reg = SY8106A_REG_VOUT1_SEL,
+ .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK,
+ /*
+ * This ramp_delay is a conservative default value which works on
+ * H3/H5 boards VDD-CPUX situations.
+ */
+ .ramp_delay = 200,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * I2C driver interface functions
+ */
+static int sy8106a_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct sy8106a *chip;
+ struct device *dev = &i2c->dev;
+ struct regulator_dev *rdev = NULL;
+ struct regulator_config config = { };
+ unsigned int reg, vsel;
+ int error;
+
+ chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ error = of_property_read_u32(dev->of_node, "silergy,fixed-microvolt",
+ &chip->fixed_voltage);
+ if (error)
+ return error;
+
+ if (chip->fixed_voltage < SY8106A_MIN_MV * 1000 ||
+ chip->fixed_voltage > SY8106A_MAX_MV * 1000)
+ return -EINVAL;
+
+ chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ error = PTR_ERR(chip->regmap);
+ dev_err(dev, "Failed to allocate register map: %d\n", error);
+ return error;
+ }
+
+ config.dev = &i2c->dev;
+ config.regmap = chip->regmap;
+ config.driver_data = chip;
+
+ config.of_node = dev->of_node;
+ config.init_data = of_get_regulator_init_data(dev, dev->of_node,
+ &sy8106a_reg);
+
+ if (!config.init_data)
+ return -ENOMEM;
+
+ /* Ensure GO_BIT is enabled when probing */
+ error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, ®);
+ if (error)
+ return error;
+
+ if (!(reg & SY8106A_GO_BIT)) {
+ vsel = (chip->fixed_voltage / 1000 - SY8106A_MIN_MV) /
+ SY8106A_STEP_MV;
+
+ error = regmap_write(chip->regmap, SY8106A_REG_VOUT1_SEL,
+ vsel | SY8106A_GO_BIT);
+ if (error)
+ return error;
+ }
+
+ /* Probe regulator */
+ rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config);
+ if (IS_ERR(rdev)) {
+ error = PTR_ERR(rdev);
+ dev_err(&i2c->dev, "Failed to register SY8106A regulator: %d\n", error);
+ return error;
+ }
+
+ chip->rdev = rdev;
+
+ i2c_set_clientdata(i2c, chip);
+
+ return 0;
+}
+
+static const struct of_device_id sy8106a_i2c_of_match[] = {
+ { .compatible = "silergy,sy8106a" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match);
+
+static const struct i2c_device_id sy8106a_i2c_id[] = {
+ { "sy8106a", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);
+
+static struct i2c_driver sy8106a_regulator_driver = {
+ .driver = {
+ .name = "sy8106a",
+ .of_match_table = of_match_ptr(sy8106a_i2c_of_match),
+ },
+ .probe = sy8106a_i2c_probe,
+ .id_table = sy8106a_i2c_id,
+};
+
+module_i2c_driver(sy8106a_regulator_driver);
+
+MODULE_AUTHOR("Ond??ej Jirman <megous@megous.com>");
+MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
+MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
+MODULE_LICENSE("GPL");
--
2.17.0
^ permalink raw reply related
* Applied "ASoC: fix return value check in mt6351_codec_driver_probe()" to the asoc tree
From: Mark Brown @ 2018-05-09 9:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525657185-73163-1-git-send-email-weiyongjun1@huawei.com>
The patch
ASoC: fix return value check in mt6351_codec_driver_probe()
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From aaa730ca3f88f535dc12e2f0ff575f70f516841b Mon Sep 17 00:00:00 2001
From: Wei Yongjun <weiyongjun1@huawei.com>
Date: Mon, 7 May 2018 01:39:45 +0000
Subject: [PATCH] ASoC: fix return value check in mt6351_codec_driver_probe()
In case of error, the function dev_get_regmap() returns NULL pointer not
ERR_PTR(). The IS_ERR() test in the return value check should be
replaced with NULL test.
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/codecs/mt6351.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c
index e739f078fec5..f73dcd753584 100644
--- a/sound/soc/codecs/mt6351.c
+++ b/sound/soc/codecs/mt6351.c
@@ -1472,8 +1472,8 @@ static int mt6351_codec_driver_probe(struct platform_device *pdev)
priv->dev = &pdev->dev;
priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
+ if (!priv->regmap)
+ return -ENODEV;
dev_dbg(priv->dev, "%s(), dev name %s\n",
__func__, dev_name(&pdev->dev));
--
2.17.0
^ permalink raw reply related
* [PATCH 4/4] drm/rockchip: support dp training outside dp firmware
From: hl @ 2018-05-09 9:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAFqH_531eY=cnuEsBbXaZRyPYjJJ0nmoqZg_QXcJN0A4tk95YQ@mail.gmail.com>
On Monday, May 07, 2018 07:29 PM, Enric Balletbo Serra wrote:
> Hi Lin,
>
> Thanks for the patch.
>
> 2018-05-04 10:08 GMT+02:00 Lin Huang <hl@rock-chips.com>:
>> DP firware use fix phy config value to do training, but some
> s/fiware/firmware/
>
>> board need to adjust these value to fit for their hardware design,
>> so we use new phy config to do training outside firmware to meet
>> this situation, if there have new phy config pass from dts, it will
>> use training outside firmware.
>>
> maybe you can rewrite all this in a better way.
>
> ooi, which boards needs this?
>
>
>> Signed-off-by: Chris Zhong <zyw@rock-chips.com>
>> Signed-off-by: Lin Huang <hl@rock-chips.com>
>> ---
>> drivers/gpu/drm/rockchip/Makefile | 3 +-
>> drivers/gpu/drm/rockchip/cdn-dp-core.c | 23 +-
>> drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 +
>> drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 398 ++++++++++++++++++++++++
>> drivers/gpu/drm/rockchip/cdn-dp-reg.c | 33 +-
>> drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++-
>> 6 files changed, 480 insertions(+), 17 deletions(-)
>> create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c
>>
>> diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
>> index a314e21..b932f62 100644
>> --- a/drivers/gpu/drm/rockchip/Makefile
>> +++ b/drivers/gpu/drm/rockchip/Makefile
>> @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
>> rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
>>
>> rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
>> -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
>> +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \
>> + cdn-dp-link-training.o
>> rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
>> rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
>> rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>> index 268c190..a2a4208 100644
>> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>> @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
>> goto out;
>> }
>> }
>> -
>> - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
>> - if (ret) {
>> - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret);
>> - goto out;
>> + if (dp->sw_training_success == false) {
>> + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
>> + if (ret) {
>> + DRM_DEV_ERROR(dp->dev,
>> + "Failed to idle video %d\n", ret);
>> + goto out;
>> + }
>> }
>>
>> ret = cdn_dp_config_video(dp);
>> @@ -642,11 +644,14 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
>> goto out;
>> }
>>
>> - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
>> - if (ret) {
>> - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret);
>> - goto out;
>> + if (dp->sw_training_success == false) {
>> + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
>> + if (ret) {
>> + DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret);
>> + goto out;
>> + }
>> }
>> +
>> out:
>> mutex_unlock(&dp->lock);
>> }
>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
>> index 46159b2..c6050ab 100644
>> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
>> @@ -84,6 +84,7 @@ struct cdn_dp_device {
>> bool connected;
>> bool active;
>> bool suspended;
>> + bool sw_training_success;
>>
>> const struct firmware *fw; /* cdn dp firmware */
>> unsigned int fw_version; /* cdn fw version */
>> @@ -106,6 +107,7 @@ struct cdn_dp_device {
>> u8 ports;
>> u8 lanes;
>> int active_port;
>> + u8 train_set[4];
>>
>> u8 dpcd[DP_RECEIVER_CAP_SIZE];
>> bool sink_has_audio;
>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c
>> new file mode 100644
>> index 0000000..558c945
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c
>> @@ -0,0 +1,398 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
> For a C source file the format is:
> (https://www.kernel.org/doc/html/latest/process/license-rules.html)
>
> // SPDX-License-Identifier: <SPDX License Expression>
Thanks for pointing it, will fix it.
>> +/*
>> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
>> + * Author: Chris Zhong <zyw@rock-chips.com>
>> + */
>> +
>> +#include <linux/arm-smccc.h>
> Why you need this include?
>
>> +#include <linux/clk.h>
>> +#include <linux/device.h>
>> +#include <linux/delay.h>
>> +#include <linux/io.h>
>> +#include <linux/iopoll.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/reset.h>
>> +#include <soc/rockchip/rockchip_phy_typec.h>
>> +
> In fact, I think that there are other includes that can be removed,
> please review.
>
>> +#include "cdn-dp-core.h"
>> +#include "cdn-dp-reg.h"
>> +
>> +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp)
>> +{
>> + struct cdn_dp_port *port = dp->port[dp->active_port];
>> + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy);
>> +
>> + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate);
>> + u8 swing = (dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) >>
>> + DP_TRAIN_VOLTAGE_SWING_SHIFT;
>> + u8 pre_emphasis = (dp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
>> + >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
>> +
>> + tcphy->typec_phy_config(port->phy, rate, dp->link.num_lanes,
>> + swing, pre_emphasis);
>> +}
>> +
>> +static int cdn_dp_set_pattern(struct cdn_dp_device *dp, uint8_t dp_train_pat)
>> +{
>> + u32 phy_config, global_config;
>> + int ret;
>> + uint8_t pattern = dp_train_pat & DP_TRAINING_PATTERN_MASK;
>> +
>> + global_config = NUM_LANES(dp->link.num_lanes - 1) | SST_MODE |
>> + GLOBAL_EN | RG_EN | ENC_RST_DIS | WR_VHSYNC_FALL;
>> +
>> + phy_config = DP_TX_PHY_ENCODER_BYPASS(0) |
>> + DP_TX_PHY_SKEW_BYPASS(0) |
>> + DP_TX_PHY_DISPARITY_RST(0) |
>> + DP_TX_PHY_LANE0_SKEW(0) |
>> + DP_TX_PHY_LANE1_SKEW(1) |
>> + DP_TX_PHY_LANE2_SKEW(2) |
>> + DP_TX_PHY_LANE3_SKEW(3) |
>> + DP_TX_PHY_10BIT_ENABLE(0);
>> +
>> + if (pattern != DP_TRAINING_PATTERN_DISABLE) {
>> + global_config |= NO_VIDEO;
>> + phy_config |= DP_TX_PHY_TRAINING_ENABLE(1) |
>> + DP_TX_PHY_SCRAMBLER_BYPASS(1) |
>> + DP_TX_PHY_TRAINING_PATTERN(pattern);
>> + }
>> +
>> + ret = cdn_dp_reg_write(dp, DP_FRAMER_GLOBAL_CONFIG, global_config);
>> + if (ret) {
>> + DRM_ERROR("fail to set DP_FRAMER_GLOBAL_CONFIG, error: %d\n",
>> + ret);
>> + return ret;
>> + }
>> +
>> + ret = cdn_dp_reg_write(dp, DP_TX_PHY_CONFIG_REG, phy_config);
>> + if (ret) {
>> + DRM_ERROR("fail to set DP_TX_PHY_CONFIG_REG, error: %d\n",
>> + ret);
>> + return ret;
>> + }
>> +
>> + ret = cdn_dp_reg_write(dp, DPTX_LANE_EN, BIT(dp->link.num_lanes) - 1);
>> + if (ret) {
>> + DRM_ERROR("fail to set DPTX_LANE_EN, error: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + if (drm_dp_enhanced_frame_cap(dp->dpcd))
>> + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 1);
>> + else
>> + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 0);
>> + if (ret)
>> + DRM_ERROR("failed to set DPTX_ENHNCD, error: %x\n", ret);
>> +
>> + return ret;
>> +}
>> +
>> +static u8 cdn_dp_pre_emphasis_max(u8 voltage_swing)
>> +{
>> + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>> + return DP_TRAIN_PRE_EMPH_LEVEL_3;
>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>> + return DP_TRAIN_PRE_EMPH_LEVEL_2;
>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>> + return DP_TRAIN_PRE_EMPH_LEVEL_1;
>> + default:
>> + return DP_TRAIN_PRE_EMPH_LEVEL_0;
>> + }
>> +}
>> +
>> +static void cdn_dp_get_adjust_train(struct cdn_dp_device *dp,
>> + uint8_t link_status[DP_LINK_STATUS_SIZE])
>> +{
>> + int i;
>> + uint8_t v = 0, p = 0;
>> + uint8_t preemph_max;
>> +
>> + for (i = 0; i < dp->link.num_lanes; i++) {
>> + v = max(v, drm_dp_get_adjust_request_voltage(link_status, i));
>> + p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status,
>> + i));
>> + }
>> +
>> + if (v >= VOLTAGE_LEVEL_2)
>> + v = VOLTAGE_LEVEL_2 | DP_TRAIN_MAX_SWING_REACHED;
>> +
>> + preemph_max = cdn_dp_pre_emphasis_max(v);
>> + if (p >= preemph_max)
>> + p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
>> +
>> + for (i = 0; i < dp->link.num_lanes; i++)
>> + dp->train_set[i] = v | p;
>> +}
>> +
>> +/*
>> + * Pick training pattern for channel equalization. Training Pattern 3 for HBR2
>> + * or 1.2 devices that support it, Training Pattern 2 otherwise.
>> + */
>> +static u32 cdn_dp_select_chaneq_pattern(struct cdn_dp_device *dp)
>> +{
>> + u32 training_pattern = DP_TRAINING_PATTERN_2;
>> +
>> + /*
>> + * cdn dp support HBR2 also support TPS3. TPS3 support is also mandatory
>> + * for downstream devices that support HBR2. However, not all sinks
>> + * follow the spec.
>> + */
>> + if (drm_dp_tps3_supported(dp->dpcd))
>> + training_pattern = DP_TRAINING_PATTERN_3;
>> + else
>> + DRM_DEBUG_KMS("5.4 Gbps link rate without sink TPS3 support\n");
>> +
>> + return training_pattern;
>> +}
>> +
>> +
>> +static bool cdn_dp_link_max_vswing_reached(struct cdn_dp_device *dp)
>> +{
>> + int lane;
>> +
>> + for (lane = 0; lane < dp->link.num_lanes; lane++)
>> + if ((dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED) == 0)
>> + return false;
>> +
>> + return true;
>> +}
>> +
>> +static int cdn_dp_update_link_train(struct cdn_dp_device *dp)
>> +{
>> + int ret;
>> +
>> + cdn_dp_set_signal_levels(dp);
>> +
>> + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
>> + dp->train_set, dp->link.num_lanes);
>> + if (ret != dp->link.num_lanes)
>> + return -EINVAL;
>> +
>> + return 0;
>> +}
>> +
>> +static int cdn_dp_set_link_train(struct cdn_dp_device *dp,
>> + uint8_t dp_train_pat)
>> +{
>> + uint8_t buf[sizeof(dp->train_set) + 1];
>> + int ret, len;
>> +
>> + buf[0] = dp_train_pat;
>> + if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
>> + DP_TRAINING_PATTERN_DISABLE) {
>> + /* don't write DP_TRAINING_LANEx_SET on disable */
>> + len = 1;
>> + } else {
>> + /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
>> + memcpy(buf + 1, dp->train_set, dp->link.num_lanes);
>> + len = dp->link.num_lanes + 1;
>> + }
>> +
>> + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_PATTERN_SET,
>> + buf, len);
>> + if (ret != len)
>> + return -EINVAL;
>> +
>> + return 0;
>> +}
>> +
>> +static int cdn_dp_reset_link_train(struct cdn_dp_device *dp,
>> + uint8_t dp_train_pat)
>> +{
>> + int ret;
>> +
>> + memset(dp->train_set, 0, sizeof(dp->train_set));
>> +
>> + cdn_dp_set_signal_levels(dp);
>> +
>> + ret = cdn_dp_set_pattern(dp, dp_train_pat);
>> + if (ret)
>> + return ret;
>> +
>> + return cdn_dp_set_link_train(dp, dp_train_pat);
>> +}
>> +
>> +/* Enable corresponding port and start training pattern 1 */
>> +static int cdn_dp_link_training_clock_recovery(struct cdn_dp_device *dp)
>> +{
>> + u8 voltage, link_config[2];
>> + u8 link_status[DP_LINK_STATUS_SIZE];
>> + u32 voltage_tries, max_vswing_tries;
>> + u32 rate, sink_max, source_max;
>> + int ret;
>> +
>> + source_max = dp->lanes;
>> + sink_max = drm_dp_max_lane_count(dp->dpcd);
>> + dp->link.num_lanes = min(source_max, sink_max);
>> +
>> + source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE);
>> + sink_max = drm_dp_max_link_rate(dp->dpcd);
>> + rate = min(source_max, sink_max);
>> + dp->link.rate = drm_dp_link_rate_to_bw_code(rate);
>> +
>> + /* Write the link configuration data */
>> + link_config[0] = dp->link.rate;
>> + link_config[1] = dp->link.num_lanes;
>> + if (drm_dp_enhanced_frame_cap(dp->dpcd))
>> + link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
>> + drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, link_config, 2);
>> +
>> + link_config[0] = 0;
>> + link_config[1] = 0;
>> + if (dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] & 0x01)
>> + link_config[1] = DP_SET_ANSI_8B10B;
>> +
>> + drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
>> +
>> + /* clock recovery */
>> + ret = cdn_dp_reset_link_train(dp, DP_TRAINING_PATTERN_1 |
>> + DP_LINK_SCRAMBLING_DISABLE);
>> + if (ret) {
>> + DRM_ERROR("failed to start link train\n");
>> + return ret;
>> + }
>> +
>> + voltage_tries = 1;
>> + max_vswing_tries = 0;
>> + for (;;) {
>> + drm_dp_link_train_clock_recovery_delay(dp->dpcd);
>> + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) !=
>> + DP_LINK_STATUS_SIZE) {
>> + DRM_ERROR("failed to get link status\n");
>> + return -EINVAL;
>> + }
>> +
>> + if (drm_dp_clock_recovery_ok(link_status, dp->link.num_lanes)) {
>> + DRM_DEBUG_KMS("clock recovery OK\n");
>> + return 0;
>> + }
>> +
>> + if (voltage_tries >= 5) {
>> + DRM_DEBUG_KMS("Same voltage tried 5 times\n");
>> + return -EINVAL;
>> + }
>> +
>> + if (max_vswing_tries >= 1) {
>> + DRM_DEBUG_KMS("Max Voltage Swing reached\n");
>> + return -EINVAL;
>> + }
>> +
>> + voltage = dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
>> +
>> + /* Update training set as requested by target */
>> + cdn_dp_get_adjust_train(dp, link_status);
>> + if (cdn_dp_update_link_train(dp)) {
>> + DRM_ERROR("failed to update link training\n");
>> + return -EINVAL;
>> + }
>> +
>> + if ((dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
>> + voltage)
>> + ++voltage_tries;
>> + else
>> + voltage_tries = 1;
>> +
>> + if (cdn_dp_link_max_vswing_reached(dp))
>> + ++max_vswing_tries;
>> + }
>> +}
>> +
>> +static int cdn_dp_link_training_channel_equalization(struct cdn_dp_device *dp)
>> +{
>> + int tries, ret;
>> + u32 training_pattern;
>> + uint8_t link_status[DP_LINK_STATUS_SIZE];
>> +
>> + training_pattern = cdn_dp_select_chaneq_pattern(dp);
>> + training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
>> +
>> + ret = cdn_dp_set_pattern(dp, training_pattern);
>> + if (ret)
>> + return ret;
>> +
>> + ret = cdn_dp_set_link_train(dp, training_pattern);
>> + if (ret) {
>> + DRM_ERROR("failed to start channel equalization\n");
>> + return ret;
>> + }
>> +
>> + for (tries = 0; tries < 5; tries++) {
>> + drm_dp_link_train_channel_eq_delay(dp->dpcd);
>> + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) !=
>> + DP_LINK_STATUS_SIZE) {
>> + DRM_ERROR("failed to get link status\n");
>> + break;
>> + }
>> +
>> + /* Make sure clock is still ok */
>> + if (!drm_dp_clock_recovery_ok(link_status, dp->link.num_lanes)) {
>> + DRM_DEBUG_KMS("Clock recovery check failed, cannot "
>> + "continue channel equalization\n");
>> + break;
>> + }
>> +
>> + if (drm_dp_channel_eq_ok(link_status, dp->link.num_lanes)) {
>> + DRM_DEBUG_KMS("Channel EQ done. DP Training "
>> + "successful\n");
>> + return 0;
>> + }
>> +
>> + /* Update training set as requested by target */
>> + cdn_dp_get_adjust_train(dp, link_status);
>> + if (cdn_dp_update_link_train(dp)) {
>> + DRM_ERROR("failed to update link training\n");
>> + break;
>> + }
>> + }
>> +
>> + /* Try 5 times, else fail and try at lower BW */
>> + if (tries == 5)
>> + DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
>> +
>> + return -EINVAL;
>> +
>> +}
>> +
>> +static int cdn_dp_stop_link_train(struct cdn_dp_device *dp)
>> +{
>> + int ret = cdn_dp_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);
>> +
>> + if (ret)
>> + return ret;
>> +
>> + return cdn_dp_set_link_train(dp, DP_TRAINING_PATTERN_DISABLE);
>> +}
>> +
>> +int cdn_dp_software_train_link(struct cdn_dp_device *dp)
>> +{
>> + int ret, stop_err;
>> +
>> + ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd,
>> + sizeof(dp->dpcd));
>> + if (ret < 0) {
>> + DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = cdn_dp_link_training_clock_recovery(dp);
>> + if (ret) {
>> + DRM_ERROR("training clock recovery fail, error: %d\n", ret);
>> + goto out;
>> + }
>> +
>> + ret = cdn_dp_link_training_channel_equalization(dp);
>> + if (ret) {
>> + DRM_ERROR("training channel equalization fail, error: %d\n",
>> + ret);
>> + goto out;
>> + }
>> +out:
>> + stop_err = cdn_dp_stop_link_train(dp);
>> + if (stop_err) {
>> + DRM_ERROR("stop training fail, error: %d\n", stop_err);
>> + return stop_err;
>> + }
>> +
>> + return ret;
>> +}
>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
>> index b2f532a..72780f1 100644
>> --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
>> @@ -17,7 +17,9 @@
>> #include <linux/delay.h>
>> #include <linux/io.h>
>> #include <linux/iopoll.h>
>> +#include <linux/phy/phy.h>
>> #include <linux/reset.h>
>> +#include <soc/rockchip/rockchip_phy_typec.h>
>>
>> #include "cdn-dp-core.h"
>> #include "cdn-dp-reg.h"
>> @@ -189,7 +191,7 @@ static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id,
>> return 0;
>> }
>>
>> -static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
>> +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
>> {
>> u8 msg[6];
>>
>> @@ -605,22 +607,41 @@ static int cdn_dp_get_training_status(struct cdn_dp_device *dp)
>> int cdn_dp_train_link(struct cdn_dp_device *dp)
>> {
>> int ret;
>> + struct cdn_dp_port *port = dp->port[dp->active_port];
>> + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy);
>>
>> + /*
>> + * DP firmware uses fixed phy config values to do training, but some
>> + * boards need to adjust these values to fit for their unique hardware
>> + * design. So if the phy is using custom config values, do software
>> + * link training instead of relying on firmware, if software training
>> + * fail, keep firmware training as a fallback if sw training fails.
>> + */
>> + if (tcphy->need_software_training) {
>> + ret = cdn_dp_software_train_link(dp);
>> + if (ret) {
>> + DRM_DEV_ERROR(dp->dev,
>> + "Failed to do software training %d\n", ret);
>> + goto do_fw_training;
>> + }
>> + cdn_dp_reg_write(dp, SOURCE_HDTX_CAR, 0xf);
> Check for an error here and act accordingly? Or doesn't matter?
yes, it need, thanks.
>
>> + dp->sw_training_success = true;
>> + return 0;
>> + }
>> +
> nit: Personally I don't like this goto. Maybe you can refactor this.
>
> if (tcphy->need_software_training) {
> ret = cdn_dp_software_train_link(dp);
> if (!ret) {
> cdn_dp_reg_write(dp, SOURCE_HDTX_CAR, 0xf);
> dp->sw_training_success = true;
> return 0;
> }
> DRM_DEV_ERROR(dp->dev, "Failed to do software training
> %d\n", ret);
> }
if check the cdn_dp_reg_write(dp, SOURCE_HDTX_CAR, 0xf) error, i think
we still need this goto.
>> +do_fw_training:
> Then remove the goto label.
>
>> + dp->sw_training_success = false;
>> ret = cdn_dp_training_start(dp);
>> if (ret) {
>> DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret);
>> return ret;
>> }
>> -
> Do not remove the new line.
>
>> ret = cdn_dp_get_training_status(dp);
>> if (ret) {
>> DRM_DEV_ERROR(dp->dev, "Failed to get training stat %d\n", ret);
>> return ret;
>> }
>> -
>> - DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate,
>> - dp->link.num_lanes);
> Why you remove this debug message?
>
>> - return ret;
>> + return 0;
>> }
>>
>> int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active)
>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
>> index aedf2dc..b60a6b2 100644
>> --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
>> @@ -137,7 +137,7 @@
>> #define HPD_EVENT_MASK 0x211c
>> #define HPD_EVENT_DET 0x2120
>>
>> -/* dpyx framer addr */
>> +/* dptx framer addr */
>> #define DP_FRAMER_GLOBAL_CONFIG 0x2200
>> #define DP_SW_RESET 0x2204
>> #define DP_FRAMER_TU 0x2208
>> @@ -431,6 +431,40 @@
>> /* Reference cycles when using lane clock as reference */
>> #define LANE_REF_CYC 0x8000
>>
>> +/* register CM_VID_CTRL */
>> +#define LANE_VID_REF_CYC(x) (((x) & (BIT(24) - 1)) << 0)
>> +#define NMVID_MEAS_TOLERANCE(x) (((x) & 0xf) << 24)
>> +
>> +/* register DP_TX_PHY_CONFIG_REG */
>> +#define DP_TX_PHY_TRAINING_ENABLE(x) ((x) & 1)
>> +#define DP_TX_PHY_TRAINING_TYPE_PRBS7 (0 << 1)
>> +#define DP_TX_PHY_TRAINING_TYPE_TPS1 (1 << 1)
>> +#define DP_TX_PHY_TRAINING_TYPE_TPS2 (2 << 1)
>> +#define DP_TX_PHY_TRAINING_TYPE_TPS3 (3 << 1)
>> +#define DP_TX_PHY_TRAINING_TYPE_TPS4 (4 << 1)
>> +#define DP_TX_PHY_TRAINING_TYPE_PLTPAT (5 << 1)
>> +#define DP_TX_PHY_TRAINING_TYPE_D10_2 (6 << 1)
>> +#define DP_TX_PHY_TRAINING_TYPE_HBR2CPAT (8 << 1)
>> +#define DP_TX_PHY_TRAINING_PATTERN(x) ((x) << 1)
>> +#define DP_TX_PHY_SCRAMBLER_BYPASS(x) (((x) & 1) << 5)
>> +#define DP_TX_PHY_ENCODER_BYPASS(x) (((x) & 1) << 6)
>> +#define DP_TX_PHY_SKEW_BYPASS(x) (((x) & 1) << 7)
>> +#define DP_TX_PHY_DISPARITY_RST(x) (((x) & 1) << 8)
>> +#define DP_TX_PHY_LANE0_SKEW(x) (((x) & 7) << 9)
>> +#define DP_TX_PHY_LANE1_SKEW(x) (((x) & 7) << 12)
>> +#define DP_TX_PHY_LANE2_SKEW(x) (((x) & 7) << 15)
>> +#define DP_TX_PHY_LANE3_SKEW(x) (((x) & 7) << 18)
>> +#define DP_TX_PHY_10BIT_ENABLE(x) (((x) & 1) << 21)
>> +
>> +/* register DP_FRAMER_GLOBAL_CONFIG */
>> +#define NUM_LANES(x) ((x) & 3)
>> +#define SST_MODE (0 << 2)
>> +#define GLOBAL_EN (1 << 3)
>> +#define RG_EN (0 << 4)
>> +#define NO_VIDEO (1 << 5)
>> +#define ENC_RST_DIS (1 << 6)
>> +#define WR_VHSYNC_FALL (1 << 7)
>> +
> Use the BIT() macros for these.
will fix it
>
>> enum voltage_swing_level {
>> VOLTAGE_LEVEL_0,
>> VOLTAGE_LEVEL_1,
>> @@ -476,6 +510,7 @@ int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip);
>> int cdn_dp_event_config(struct cdn_dp_device *dp);
>> u32 cdn_dp_get_event(struct cdn_dp_device *dp);
>> int cdn_dp_get_hpd_status(struct cdn_dp_device *dp);
>> +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val);
>> ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr,
>> u8 *data, u16 len);
>> ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr,
>> @@ -489,4 +524,5 @@ int cdn_dp_config_video(struct cdn_dp_device *dp);
>> int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio);
>> int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable);
>> int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio);
>> +int cdn_dp_software_train_link(struct cdn_dp_device *dp);
>> #endif /* _CDN_DP_REG_H */
>> --
>> 2.7.4
>>
>
>
^ permalink raw reply
* Applied "ASoC: uniphier: evea: use DAPM to change source of line-in" to the asoc tree
From: Mark Brown @ 2018-05-09 9:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508084509.21616-1-suzuki.katsuhiro@socionext.com>
The patch
ASoC: uniphier: evea: use DAPM to change source of line-in
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From e5ba319882d78030b054dee4eeaf758340b2756f Mon Sep 17 00:00:00 2001
From: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Date: Tue, 8 May 2018 17:45:09 +0900
Subject: [PATCH] ASoC: uniphier: evea: use DAPM to change source of line-in
This patch replaces mixer switch to DAPM one for changing audio source
of line-in.
Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/uniphier/evea.c | 55 +++++++++++++++++++++++----------------
1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c
index 73fd6730095c..f9c10165fbc1 100644
--- a/sound/soc/uniphier/evea.c
+++ b/sound/soc/uniphier/evea.c
@@ -54,8 +54,21 @@ struct evea_priv {
int switch_hp;
};
+static const char * const linsw1_sel1_text[] = {
+ "LIN1", "LIN2", "LIN3"
+};
+
+static SOC_ENUM_SINGLE_DECL(linsw1_sel1_enum,
+ ALINSW1, ALINSW1_SEL1_SHIFT,
+ linsw1_sel1_text);
+
+static const struct snd_kcontrol_new linesw1_mux[] = {
+ SOC_DAPM_ENUM("Line In 1 Source", linsw1_sel1_enum),
+};
+
static const struct snd_soc_dapm_widget evea_widgets[] = {
- SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_MUX("Line In 1 Mux", SND_SOC_NOPM, 0, 0, linesw1_mux),
SND_SOC_DAPM_INPUT("LIN1_LP"),
SND_SOC_DAPM_INPUT("LIN1_RP"),
SND_SOC_DAPM_INPUT("LIN2_LP"),
@@ -63,7 +76,9 @@ static const struct snd_soc_dapm_widget evea_widgets[] = {
SND_SOC_DAPM_INPUT("LIN3_LP"),
SND_SOC_DAPM_INPUT("LIN3_RP"),
- SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC HP", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC LO1", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC LO2", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUTPUT("HP1_L"),
SND_SOC_DAPM_OUTPUT("HP1_R"),
SND_SOC_DAPM_OUTPUT("LO2_L"),
@@ -71,17 +86,22 @@ static const struct snd_soc_dapm_widget evea_widgets[] = {
};
static const struct snd_soc_dapm_route evea_routes[] = {
- { "ADC", NULL, "LIN1_LP" },
- { "ADC", NULL, "LIN1_RP" },
- { "ADC", NULL, "LIN2_LP" },
- { "ADC", NULL, "LIN2_RP" },
- { "ADC", NULL, "LIN3_LP" },
- { "ADC", NULL, "LIN3_RP" },
-
- { "HP1_L", NULL, "DAC" },
- { "HP1_R", NULL, "DAC" },
- { "LO2_L", NULL, "DAC" },
- { "LO2_R", NULL, "DAC" },
+ { "Line In 1", NULL, "ADC" },
+ { "ADC", NULL, "Line In 1 Mux" },
+ { "Line In 1 Mux", "LIN1", "LIN1_LP" },
+ { "Line In 1 Mux", "LIN1", "LIN1_RP" },
+ { "Line In 1 Mux", "LIN2", "LIN2_LP" },
+ { "Line In 1 Mux", "LIN2", "LIN2_RP" },
+ { "Line In 1 Mux", "LIN3", "LIN3_LP" },
+ { "Line In 1 Mux", "LIN3", "LIN3_RP" },
+
+ { "DAC HP", NULL, "Headphone 1" },
+ { "DAC LO1", NULL, "Line Out 1" },
+ { "DAC LO2", NULL, "Line Out 2" },
+ { "HP1_L", NULL, "DAC HP" },
+ { "HP1_R", NULL, "DAC HP" },
+ { "LO2_L", NULL, "DAC LO2" },
+ { "LO2_R", NULL, "DAC LO2" },
};
static void evea_set_power_state_on(struct evea_priv *evea)
@@ -280,16 +300,7 @@ static int evea_set_switch_hp(struct snd_kcontrol *kcontrol,
return evea_update_switch_hp(evea);
}
-static const char * const linsw1_sel1_text[] = {
- "LIN1", "LIN2", "LIN3"
-};
-
-static SOC_ENUM_SINGLE_DECL(linsw1_sel1_enum,
- ALINSW1, ALINSW1_SEL1_SHIFT,
- linsw1_sel1_text);
-
static const struct snd_kcontrol_new evea_controls[] = {
- SOC_ENUM("Line Capture Source", linsw1_sel1_enum),
SOC_SINGLE_BOOL_EXT("Line Capture Switch", 0,
evea_get_switch_lin, evea_set_switch_lin),
SOC_SINGLE_BOOL_EXT("Line Playback Switch", 0,
--
2.17.0
^ permalink raw reply related
* [PATCH v6 07/15] KVM: arm64: Optimise FPSIMD handling to reduce guest/host thrashing
From: Marc Zyngier @ 2018-05-09 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180509091701.GM7753@e103592.cambridge.arm.com>
On 09/05/18 10:17, Dave Martin wrote:
> On Wed, May 09, 2018 at 09:24:36AM +0100, Marc Zyngier wrote:
>> On 08/05/18 17:44, Dave Martin wrote:
>>> This patch refactors KVM to align the host and guest FPSIMD
>>> save/restore logic with each other for arm64. This reduces the
>
> [...]
>
>>> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
>>> index 9699c13..6429eb6 100644
>>> --- a/arch/arm64/include/asm/kvm_asm.h
>>> +++ b/arch/arm64/include/asm/kvm_asm.h
>>> @@ -33,6 +33,8 @@
>>> /* vcpu_arch flags field values: */
>>> #define KVM_ARM64_DEBUG_DIRTY_SHIFT 0
>>> #define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
>>
>> At some point, we could remove KVM_ARM64_DEBUG_DIRTY_SHIFT as it is not
>> used anymore (since 1ea66d27e7b0). Do not respin on this account though.
>
> I wondered about this... I presume this was used from assembly once
> upon a time.
>
> Since I need to repost for something else anyway, shall I delete that
> and move the defines to kvm_host.h? There's no longer an obvious reason
> for them to be in a different header.
Yes, please.
> [...]
>
>>> diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
>>> new file mode 100644
>>> index 0000000..7059275
>>> --- /dev/null
>>> +++ b/arch/arm64/kvm/fpsimd.c
>>> @@ -0,0 +1,111 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * arch/arm64/kvm/fpsimd.c: Guest/host FPSIMD context coordination helpers
>>> + *
>>> + * Copyright 2018 Arm Limited
>>> + * Author: Dave Martin <Dave.Martin@arm.com>
>>> + */
>>> +#include <linux/bottom_half.h>
>>> +#include <linux/sched.h>
>>> +#include <linux/thread_info.h>
>>> +#include <linux/kvm_host.h>
>>> +#include <asm/kvm_asm.h>
>>> +#include <asm/kvm_host.h>
>>> +#include <asm/kvm_mmu.h>
>>> +
>>> +/*
>>> + * Called on entry to KVM_RUN unless this vcpu previously ran at least
>>> + * once and the most recent prior KVM_RUN for this vcpu was called from
>>> + * the same task as current (highly likely).
>>> + *
>>> + * This is guaranteed to execute before kvm_arch_vcpu_load_fp(vcpu),
>>> + * such that on entering hyp the relevant parts of current are already
>>> + * mapped.
>>> + */
>>> +int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu)
>>> +{
>>> + int ret;
>>> +
>>> + struct thread_info *ti = ¤t->thread_info;
>>> + struct user_fpsimd_state *fpsimd = ¤t->thread.uw.fpsimd_state;
>>> +
>>> + /*
>>> + * Make sure the host task thread flags and fpsimd state are
>>> + * visible to hyp:
>>> + */
>>> + ret = create_hyp_mappings(ti, ti + 1, PAGE_HYP);
>>> + if (ret)
>>> + goto error;
>>> +
>>> + ret = create_hyp_mappings(fpsimd, fpsimd + 1, PAGE_HYP);
>>> + if (ret)
>>> + goto error;
>>> +
>>> + vcpu->arch.host_thread_info = kern_hyp_va(ti);
>>> + vcpu->arch.host_fpsimd_state = kern_hyp_va(fpsimd);
>>
>> Since we assign host_fpsimd_state here, and that "map" is guaranteed to
>> execute before "load"...
>>
>>> +error:
>>> + return ret;
>>> +}
>>> +
>>> +/*
>>> + * Prepare vcpu for saving the host's FPSIMD state and loading the guest's.
>>> + * The actual loading is done by the FPSIMD access trap taken to hyp.
>>> + *
>>> + * Here, we just set the correct metadata to indicate that the FPSIMD
>>> + * state in the cpu regs (if any) belongs to current, and where to write
>>> + * it back to if/when a FPSIMD access trap is taken.
>>> + *
>>> + * TIF_SVE is backed up here, since it may get clobbered with guest state.
>>> + * This flag is restored by kvm_arch_vcpu_put_fp(vcpu).
>>> + */
>>> +void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
>>> +{
>>> + BUG_ON(system_supports_sve());
>>> + BUG_ON(!current->mm);
>>> +
>>> + vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED | KVM_ARM64_HOST_SVE_IN_USE);
>>> + if (test_thread_flag(TIF_SVE))
>>> + vcpu->arch.flags |= KVM_ARM64_HOST_SVE_IN_USE;
>>> +
>>> + vcpu->arch.host_fpsimd_state =
>>> + kern_hyp_va(¤t->thread.uw.fpsimd_state);
>>
>> ... what is the purpose of this assignment? I don't think it is harmful
>> in any way, but I'm just wondering if I'm missing in the actual flow.
>
> The pointer will be NULLed by __hyp_switch_fpsimd() when loading the
> guest state in, to indicate that there is no longer any host state to
> save. Perhaps it would have been clearer to have a separate flag to
> represent this change of state.
>
> As things stand I think you're right: the assignments are redundant.
> We certainly need the pointer to reflect the current task, which is
> the motivation for doing it here -- but in fact we need to do it
> more often, at every vcpu_load().
>
> I think the most appropriate thing is to delete the assignment from
> _map_fp().
>
> The alternative would be to add a flag for the "no host state to save"
> case, and fpsimd_host_state only in the pid_change hook.
I think I'd prefer the latter. It makes the whole pointer stuff a lot
easier to understand (the linkages are basically static), and using
flags is consistent with the way the rest of the kernel works. I'm not
sure whether we need to add a new flag or simply rely on the existing
thread flag, but that for you to decide.
>
> [...]
>
>>> +/*
>>> + * Write back the vcpu FPSIMD regs if they are dirty, and invalidate the
>>> + * cpu FPSIMD regs so that they can't be spuriously reused if this vcpu
>>> + * disappears and another task or vcpu appears that recycles the same
>>> + * struct fpsimd_state.
>>> + */
>>> +void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
>>> +{
>>> + local_bh_disable();
>>> +
>>> + if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
>>> + fpsimd_save();
>>> + fpsimd_flush_cpu_state();
>>> + set_thread_flag(TIF_FOREIGN_FPSTATE);
>>> + }
>>> +
>>> + update_thread_flag(TIF_SVE,
>>> + vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE);
>>
>> Does this indicate anything about the validity of the SVE registers? Or
>> is it for the sole purpose of userspace not having to trap to re-enable SVE?
>
> This is the host task's "SVE registers exist" flag. It's essential to
> restore this correctly before re-enabling preemption, because it
> controls where the regs are saved/restored from:
> current->thread.fpsimd_state, or the dynamically allocated buffer
> current->thread.sve_state (TIF_SVE set indicates the latter).
>
> TIF_FOREIGN_FPSTATE is orthogonal to this, and indicates whether the
> regs are actually loaded in the hardware. Obviously they aren't if
> we had loaded the guest's regs meanwhile.
OK, that makes sense now.
> [...]
>
>>> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
>>> index c0796c4..75c3b65 100644
>>> --- a/arch/arm64/kvm/hyp/switch.c
>>> +++ b/arch/arm64/kvm/hyp/switch.c
>>> @@ -27,15 +27,16 @@
>>> #include <asm/kvm_mmu.h>
>>> #include <asm/fpsimd.h>
>>> #include <asm/debug-monitors.h>
>>> +#include <asm/thread_info.h>
>>>
>>> -static bool __hyp_text __fpsimd_enabled_nvhe(void)
>>> +static bool __hyp_text update_fp_enabled(struct kvm_vcpu *vcpu)
>>> {
>>> - return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
>>> -}
>>> + if (vcpu->arch.host_thread_info->flags & _TIF_FOREIGN_FPSTATE) {
>>> + vcpu->arch.host_fpsimd_state = NULL;
>>> + vcpu->arch.flags &= ~KVM_ARM64_FP_ENABLED;
>>> + }
>>
>> I must confess I don't get this bit. If we started off with an invalid
>> host state (which is how I interpret TIF_FOREIGN_FPSTATE), why didn't we
>> simply zero the pointer at load time? The thread flag cannot change in
>> the meantime, right? Or did I get that wrong?
>
> The host kernel can take interrupts in the run loop while outside the
> guest, causing this flag to get set. So we really do need to re-check
> on each entry to the guest.
>
> I can add a one-line comment documenting the purpose of this function,
> which should help understanding here, something like:
>
> /* Check whether the FP regs were dirtied while in the host-side run loop */
Yup, looks good.
> [...]
>
>> It otherwise looks good, and I don't think the above nits are
>> problematic on their own.
>>
>> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
>
> Thanks.
>
> I will probably address the nits since I need to fix another build break
> issue with CONFIG_KVM=n. That will be a pretty trivial respin.
>
> Happy to keep your Reviewed-by with the discussed changes?
Yes, no problem. I'll eyeball the changes and let you know if I spot
anything.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [RFC PATCH] driver core: make deferring probe forever optional
From: Alexander Graf @ 2018-05-09 9:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507183106.GF2259@tuxbook-pro>
On 05/07/2018 08:31 PM, Bjorn Andersson wrote:
> On Tue 01 May 14:31 PDT 2018, Rob Herring wrote:
>
>> Deferred probe will currently wait forever on dependent devices to probe,
>> but sometimes a driver will never exist. It's also not always critical for
>> a driver to exist. Platforms can rely on default configuration from the
>> bootloader or reset defaults for things such as pinctrl and power domains.
> But how do you know if this is the case?
>
>> This is often the case with initial platform support until various drivers
>> get enabled.
> Can you please name platform that has enough support for Alexander to
> care about backwards and forwards compatibility but lacks a pinctrl
> driver.
ZynqMP is one example that immediately comes to my mind. I'm sure there
are others too.
In general it's very frustrating to debug what goes wrong when you can't
even get serial to output anything at all just because there are now
pinctrl bindings that your kernel may not know about yet. I've run into
that too many times.
>
>> There's at least 2 scenarios where deferred probe can render
>> a platform broken. Both involve using a DT which has more devices and
>> dependencies than the kernel supports. The 1st case is a driver may be
>> disabled in the kernel config.
> I agree that there is a chance that you _might_ get some parts of the
> system working by relying on the boot loader configuration, but
> misconfiguration issues applies to any other fundamental providers, such
> as clocks, regulators, power domains and gpios as well.
>
>> The 2nd case is the kernel version may
>> simply not have the dependent driver. This can happen if using a newer DT
>> (provided by firmware perhaps) with a stable kernel version.
>>
> As above, this is in no way limited to pinctrl drivers.
>
>> Unfortunately, this change breaks with modules as we have no way of
>> knowing when modules are done loading. One possibility is to make this
>> opt in or out based on compatible strings rather than at a subsystem level.
>> Ideally this information could be extracted automatically somehow. OTOH,
>> maybe the lists are pretty small. There's only a handful of subsystems
>> that can be optional, and then only so many drivers in those that can be
>> modules (at least for pinctrl, many drivers are built-in only).
>>
> On the Qualcomm platform most drivers are tristate and on most platforms
> there are size restrictions in the proprietary boot loader preventing us
> from boot the kernel after switching all these frameworks from tristate
> to bool (which feels like a more appropriate solution than your hack).
I don't see how setting them to bool contradicts with the hack? The goal
of this patch is to allow systems to load drivers on firmware provided
pinctrl setups if there is no matching pinctrl driver in the kernel.
>
>> Cc: Alexander Graf <agraf@suse.de>
>> Signed-off-by: Rob Herring <robh@kernel.org>
>> ---
>> This patch came out of a discussion on the ARM boot-architecture
>> list[1] about DT forwards and backwards compatibility issues. There are
>> issues with newer DTs breaking on older, stable kernels. Some of these
>> are difficult to solve, but cases of optional devices not having
>> kernel support should be solvable.
>>
> There are two cases here:
> 1) DT contains compatibles that isn't supported by the kernel. In this
> case the associated device will remain in the probe deferral list and
> user space won't know about the device.
>
> 2) DT contains compatibles known to the kernel but has new optional
> properties that makes things functional or works around hardware bugs.
The key point is not to regress. Imagine you have firmware 1.0 which
works with OS 1.0. Firmware provides the device tree.
When you update to firmware to 1.1 you want to make sure OS 1.0 still
works. The bug you're referring to that existed before of course still
exists. But we're not worse off.
>
>> I tested this on a RPi3 B with the pinctrl driver forced off. With this
>> change, the MMC/SD and UART drivers can function without the pinctrl
>> driver.
>>
> Cool, so what about graphics, audio, networking, usb and all the other
> things that people actually expect when they _use_ a distro?
Again, it's about regressions. If audio didn't work before, a firmware
update may not get you working audio with OS 1.0. But it may enable OS
1.1 to provide audio.
Alex
^ permalink raw reply
* [PATCH v7 20/24] ASoC: qdsp6: q6afe: Add q6afe dai driver
From: Srinivas Kandagatla @ 2018-05-09 9:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <22a39a17-36ef-3e94-e91b-11d303559ae4@codeaurora.org>
On 09/05/18 10:42, Banajit Goswami wrote:
>> +
>> +static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
>> +{
>> + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
>> + struct snd_soc_dapm_context *dapm;
>> + struct q6afe_port *port;
>> +
>> + dapm = snd_soc_component_get_dapm(dai->component);
> dapm unused here?
>
I already removed this in v8.
thanks,
srini
> LGTM otherwise.
> Acked-by: Banajit Goswami <bgoswami@codeaurora.org>
>
> --
^ permalink raw reply
* [PATCH] mtd: nxp-spifi: decrement flash_np refcnt on error paths
From: Boris Brezillon @ 2018-05-09 9:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525812456-25877-1-git-send-email-khoroshilov@ispras.ru>
On Tue, 8 May 2018 23:47:36 +0300
Alexey Khoroshilov <khoroshilov@ispras.ru> wrote:
> nxp_spifi_probe() increments refcnt of SPI flash device node by
> of_get_next_available_child() and then it passes the node
> to mtd device in nxp_spifi_setup_flash().
> But if a failure happens before mtd_device_register() succeed,
> the refcnt is left undecremented.
Why not doing that in the error path of the probe function? Also, you
probably want to call of_node_put() in the ->remove() function.
>
> Found by Linux Driver Verification project (linuxtesting.org).
>
> Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
> ---
> drivers/mtd/spi-nor/nxp-spifi.c | 16 +++++++++++-----
> 1 file changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c
> index 15374216d4d9..8919e31f2ab8 100644
> --- a/drivers/mtd/spi-nor/nxp-spifi.c
> +++ b/drivers/mtd/spi-nor/nxp-spifi.c
> @@ -294,7 +294,8 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
> break;
> default:
> dev_err(spifi->dev, "unsupported rx-bus-width\n");
> - return -EINVAL;
> + ret = -EINVAL;
> + goto err_node_put;
> }
> }
>
> @@ -328,7 +329,8 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
> break;
> default:
> dev_err(spifi->dev, "only mode 0 and 3 supported\n");
> - return -EINVAL;
> + ret = -EINVAL;
> + goto err_node_put;
> }
>
> writel(ctrl, spifi->io_base + SPIFI_CTRL);
> @@ -356,22 +358,26 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
> ret = spi_nor_scan(&spifi->nor, NULL, &hwcaps);
> if (ret) {
> dev_err(spifi->dev, "device scan failed\n");
> - return ret;
> + goto err_node_put;
> }
>
> ret = nxp_spifi_setup_memory_cmd(spifi);
> if (ret) {
> dev_err(spifi->dev, "memory command setup failed\n");
> - return ret;
> + goto err_node_put;
> }
>
> ret = mtd_device_register(&spifi->nor.mtd, NULL, 0);
> if (ret) {
> dev_err(spifi->dev, "mtd device parse failed\n");
> - return ret;
> + goto err_node_put;
> }
>
> return 0;
> +
> +err_node_put:
> + of_node_put(np);
> + return ret;
> }
>
> static int nxp_spifi_probe(struct platform_device *pdev)
^ permalink raw reply
* [PATCH v7 20/24] ASoC: qdsp6: q6afe: Add q6afe dai driver
From: Banajit Goswami @ 2018-05-09 9:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180501120820.11016-21-srinivas.kandagatla@linaro.org>
On 5/1/2018 5:08 AM, Srinivas Kandagatla wrote:
> This patch adds support to q6afe backend dais driver.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Reviewed-and-tested-by: Rohit kumar <rohitkr@codeaurora.org>
> ---
> sound/soc/qcom/Kconfig | 4 +
> sound/soc/qcom/qdsp6/Makefile | 1 +
> sound/soc/qcom/qdsp6/q6afe-dai.c | 752 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 757 insertions(+)
> create mode 100644 sound/soc/qcom/qdsp6/q6afe-dai.c
>
> diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
> index 43f9ed85efa8..d3523a30d942 100644
> --- a/sound/soc/qcom/Kconfig
<snip>
> +};
> +
> +static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
> +{
> + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
> + struct snd_soc_dapm_context *dapm;
> + struct q6afe_port *port;
> +
> + dapm = snd_soc_component_get_dapm(dai->component);
dapm unused here?
LGTM otherwise.
Acked-by: Banajit Goswami <bgoswami@codeaurora.org>
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Applied "ASoC: uniphier: add digital output volume for UniPhier sound system" to the asoc tree
From: Mark Brown @ 2018-05-09 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508031639.24648-1-suzuki.katsuhiro@socionext.com>
The patch
ASoC: uniphier: add digital output volume for UniPhier sound system
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 5a748de0644d16ceb4192ebf785742619b88109b Mon Sep 17 00:00:00 2001
From: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Date: Tue, 8 May 2018 12:16:39 +0900
Subject: [PATCH] ASoC: uniphier: add digital output volume for UniPhier sound
system
This patch adds controllers for digital volume of PCM output. Volume
effects simply linear, not dB scale as follows:
Gained PCM = Original * 0x4000 / Volume
The value range of volume is from 0x0001 to 0xffff. 0x0000 works as
mute. Initial value is 0x4000 (+0dB).
Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/uniphier/aio-core.c | 58 ++++++++++++++
sound/soc/uniphier/aio-cpu.c | 140 ++++++++++++++++++++++++++++++++++
sound/soc/uniphier/aio-reg.h | 33 ++++++--
sound/soc/uniphier/aio.h | 7 ++
4 files changed, 233 insertions(+), 5 deletions(-)
diff --git a/sound/soc/uniphier/aio-core.c b/sound/soc/uniphier/aio-core.c
index e37b80921abb..638cb3fc5f7b 100644
--- a/sound/soc/uniphier/aio-core.c
+++ b/sound/soc/uniphier/aio-core.c
@@ -659,6 +659,64 @@ void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
}
}
+/**
+ * aio_port_get_volume - get volume of AIO port block
+ * @sub: the AIO substream pointer
+ *
+ * Return: current volume, range is 0x0000 - 0xffff
+ */
+int aio_port_get_volume(struct uniphier_aio_sub *sub)
+{
+ struct regmap *r = sub->aio->chip->regmap;
+ u32 v;
+
+ regmap_read(r, OPORTMXTYVOLGAINSTATUS(sub->swm->oport.map, 0), &v);
+
+ return FIELD_GET(OPORTMXTYVOLGAINSTATUS_CUR_MASK, v);
+}
+
+/**
+ * aio_port_set_volume - set volume of AIO port block
+ * @sub: the AIO substream pointer
+ * @vol: target volume, range is 0x0000 - 0xffff.
+ *
+ * Change digital volume and perfome fade-out/fade-in effect for specified
+ * output slot of port. Gained PCM value can calculate as the following:
+ * Gained = Original * vol / 0x4000
+ */
+void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
+{
+ struct regmap *r = sub->aio->chip->regmap;
+ int oport_map = sub->swm->oport.map;
+ int cur, diff, slope = 0, fs;
+
+ if (sub->swm->dir == PORT_DIR_INPUT)
+ return;
+
+ cur = aio_port_get_volume(sub);
+ diff = abs(vol - cur);
+ fs = params_rate(&sub->params);
+ if (fs)
+ slope = diff / AUD_VOL_FADE_TIME * 1000 / fs;
+ slope = max(1, slope);
+
+ regmap_update_bits(r, OPORTMXTYVOLPARA1(oport_map, 0),
+ OPORTMXTYVOLPARA1_SLOPEU_MASK, slope << 16);
+ regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
+ OPORTMXTYVOLPARA2_TARGET_MASK, vol);
+
+ if (cur < vol)
+ regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
+ OPORTMXTYVOLPARA2_FADE_MASK,
+ OPORTMXTYVOLPARA2_FADE_FADEIN);
+ else
+ regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
+ OPORTMXTYVOLPARA2_FADE_MASK,
+ OPORTMXTYVOLPARA2_FADE_FADEOUT);
+
+ regmap_write(r, AOUTFADECTR0, BIT(oport_map));
+}
+
/**
* aio_if_set_param - set parameters of AIO DMA I/F block
* @sub: the AIO substream pointer
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
index 00b6441bf195..80daec17be25 100644
--- a/sound/soc/uniphier/aio-cpu.c
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -32,6 +32,35 @@ static bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
return chip->plls[pll_id].enable;
}
+/**
+ * find_volume - find volume supported HW port by HW port number
+ * @chip: the AIO chip pointer
+ * @oport_hw: HW port number, one of AUD_HW_XXXX
+ *
+ * Find AIO device from device list by HW port number. Volume feature is
+ * available only in Output and PCM ports, this limitation comes from HW
+ * specifications.
+ *
+ * Return: The pointer of AIO substream if successful, otherwise NULL on error.
+ */
+static struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip,
+ int oport_hw)
+{
+ int i;
+
+ for (i = 0; i < chip->num_aios; i++) {
+ struct uniphier_aio_sub *sub = &chip->aios[i].sub[0];
+
+ if (!sub->swm)
+ continue;
+
+ if (sub->swm->oport.hw == oport_hw)
+ return sub;
+ }
+
+ return NULL;
+}
+
static bool match_spec(const struct uniphier_aio_spec *spec,
const char *name, int dir)
{
@@ -287,6 +316,7 @@ static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
sub->setting = 1;
aio_port_reset(sub);
+ aio_port_set_volume(sub, sub->vol);
aio_src_reset(sub);
return 0;
@@ -373,6 +403,8 @@ int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
sub->swm = &spec->swm;
sub->spec = spec;
+
+ sub->vol = AUD_VOL_INIT;
}
aio_iecout_set_enable(aio->chip, true);
@@ -449,8 +481,116 @@ int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
}
EXPORT_SYMBOL_GPL(uniphier_aio_dai_resume);
+static int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = AUD_VOL_MAX;
+
+ return 0;
+}
+
+static int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
+ struct uniphier_aio_sub *sub;
+ int oport_hw = kcontrol->private_value;
+
+ sub = find_volume(chip, oport_hw);
+ if (!sub)
+ return 0;
+
+ ucontrol->value.integer.value[0] = sub->vol;
+
+ return 0;
+}
+
+static int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
+ struct uniphier_aio_sub *sub;
+ int oport_hw = kcontrol->private_value;
+
+ sub = find_volume(chip, oport_hw);
+ if (!sub)
+ return 0;
+
+ if (sub->vol == ucontrol->value.integer.value[0])
+ return 0;
+ sub->vol = ucontrol->value.integer.value[0];
+
+ aio_port_set_volume(sub, sub->vol);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new uniphier_aio_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "HPCMOUT1 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_HPCMOUT1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "PCMOUT1 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_PCMOUT1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "PCMOUT2 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_PCMOUT2,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "PCMOUT3 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_PCMOUT3,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "HIECOUT1 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_HIECOUT1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "IECOUT1 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_IECOUT1,
+ },
+};
+
static const struct snd_soc_component_driver uniphier_aio_component = {
.name = "uniphier-aio",
+ .controls = uniphier_aio_controls,
+ .num_controls = ARRAY_SIZE(uniphier_aio_controls),
};
int uniphier_aio_probe(struct platform_device *pdev)
diff --git a/sound/soc/uniphier/aio-reg.h b/sound/soc/uniphier/aio-reg.h
index 511ea3c01847..45fdc6ae358a 100644
--- a/sound/soc/uniphier/aio-reg.h
+++ b/sound/soc/uniphier/aio-reg.h
@@ -169,6 +169,7 @@
#define PBINMXPAUSECTR1(n) (0x20208 + 0x40 * (n))
/* AOUT */
+#define AOUTFADECTR0 0x40020
#define AOUTENCTR0 0x40040
#define AOUTENCTR1 0x40044
#define AOUTENCTR2 0x40048
@@ -179,6 +180,9 @@
#define AOUTSRCRSTCTR1 0x400c4
#define AOUTSRCRSTCTR2 0x400c8
+/* AOUT PCMOUT has 5 slots, slot0-3: D0-3, slot4: DMIX */
+#define OPORT_SLOT_MAX 5
+
/* AOUT(PCMOUTN) */
#define OPORTMXCTR1(n) (0x42000 + 0x400 * (n))
#define OPORTMXCTR1_I2SLRSEL_MASK (0x11 << 10)
@@ -359,11 +363,30 @@
#define OPORTMXMASK_XCKMSK_ON (0x0 << 0)
#define OPORTMXMASK_XCKMSK_OFF (0x7 << 0)
#define OPORTMXDEBUG(n) (0x420fc + 0x400 * (n))
-#define OPORTMXT0RSTCTR(n) (0x4211c + 0x400 * (n))
-#define OPORTMXT1RSTCTR(n) (0x4213c + 0x400 * (n))
-#define OPORTMXT2RSTCTR(n) (0x4215c + 0x400 * (n))
-#define OPORTMXT3RSTCTR(n) (0x4217c + 0x400 * (n))
-#define OPORTMXT4RSTCTR(n) (0x4219c + 0x400 * (n))
+#define OPORTMXTYVOLPARA1(n, m) (0x42100 + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXTYVOLPARA1_SLOPEU_MASK GENMASK(31, 16)
+#define OPORTMXTYVOLPARA2(n, m) (0x42104 + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXTYVOLPARA2_FADE_MASK GENMASK(17, 16)
+#define OPORTMXTYVOLPARA2_FADE_NOOP (0x0 << 16)
+#define OPORTMXTYVOLPARA2_FADE_FADEOUT (0x1 << 16)
+#define OPORTMXTYVOLPARA2_FADE_FADEIN (0x2 << 16)
+#define OPORTMXTYVOLPARA2_TARGET_MASK GENMASK(15, 0)
+#define OPORTMXTYVOLGAINSTATUS(n, m) (0x42108 + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXTYVOLGAINSTATUS_CUR_MASK GENMASK(15, 0)
+#define OPORTMXTYSLOTCTR(n, m) (0x42114 + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXTYSLOTCTR_SLOTSEL_MASK GENMASK(11, 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT0 (0x8 << 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT1 (0x9 << 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT2 (0xa << 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT3 (0xb << 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT4 (0xc << 8)
+#define OPORTMXT0SLOTCTR_MUTEOFF_MASK BIT(1)
+#define OPORTMXT0SLOTCTR_MUTEOFF_MUTE (0x0 << 1)
+#define OPORTMXT0SLOTCTR_MUTEOFF_UNMUTE (0x1 << 1)
+#define OPORTMXTYRSTCTR(n, m) (0x4211c + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXT0RSTCTR_RST_MASK BIT(1)
+#define OPORTMXT0RSTCTR_RST_OFF (0x0 << 1)
+#define OPORTMXT0RSTCTR_RST_ON (0x1 << 1)
#define SBF_(frame, shift) (((frame) * 2 - 1) << shift)
diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h
index 52670126084f..aa89c2f6fa24 100644
--- a/sound/soc/uniphier/aio.h
+++ b/sound/soc/uniphier/aio.h
@@ -130,6 +130,10 @@ enum IEC61937_PC {
#define AUD_PLLDIV_1_1 2
#define AUD_PLLDIV_2_3 3
+#define AUD_VOL_INIT 0x4000 /* +0dB */
+#define AUD_VOL_MAX 0xffff /* +6dB */
+#define AUD_VOL_FADE_TIME 20 /* 20ms */
+
#define AUD_RING_SIZE (128 * 1024)
#define AUD_MIN_FRAGMENT 4
@@ -231,6 +235,7 @@ struct uniphier_aio_sub {
/* For PCM audio */
struct snd_pcm_substream *substream;
struct snd_pcm_hw_params params;
+ int vol;
/* For compress audio */
struct snd_compr_stream *cstream;
@@ -323,6 +328,8 @@ int aio_port_set_clk(struct uniphier_aio_sub *sub);
int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
const struct snd_pcm_hw_params *params);
void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable);
+int aio_port_get_volume(struct uniphier_aio_sub *sub);
+void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol);
int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through);
int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
enum IEC61937_PC pc);
--
2.17.0
^ permalink raw reply related
* Applied "regulator: add binding for the SY8106A voltage regulator" to the regulator tree
From: Mark Brown @ 2018-05-09 9:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180423144657.63264-2-icenowy@aosc.io>
The patch
regulator: add binding for the SY8106A voltage regulator
has been applied to the regulator tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 32aba834f2a9fe126ff5e624371113ac1defa06e Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 7 May 2018 20:29:40 +0800
Subject: [PATCH] regulator: add binding for the SY8106A voltage regulator
SY8106A is an I2C-controlled adjustable voltage regulator made by
Silergy Corp.
Add its device tree binding.
Signed-off-by: Ondrej Jirman <megous@megous.com>
[Icenowy: Change commit message and slight fixes]
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
.../bindings/regulator/sy8106a-regulator.txt | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
diff --git a/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
new file mode 100644
index 000000000000..39a8ca73f572
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
@@ -0,0 +1,23 @@
+SY8106A Voltage regulator
+
+Required properties:
+- compatible: Must be "silergy,sy8106a"
+- reg: I2C slave address - must be <0x65>
+- silergy,fixed-microvolt - the voltage when I2C regulating is disabled (set
+ by external resistor like a fixed voltage)
+
+Any property defined as part of the core regulator binding, defined in
+./regulator.txt, can also be used.
+
+Example:
+
+ sy8106a {
+ compatible = "silergy,sy8106a";
+ reg = <0x65>;
+ regulator-name = "sy8106a-vdd";
+ silergy,fixed-microvolt = <1200000>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
--
2.17.0
^ permalink raw reply related
* Applied "regulator: add support for SY8106A regulator" to the regulator tree
From: Mark Brown @ 2018-05-09 9:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507122942.25758-3-icenowy@aosc.io>
The patch
regulator: add support for SY8106A regulator
has been applied to the regulator tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 8878302ebbc580d64f390c0acc509e5e8276598c Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 7 May 2018 20:29:41 +0800
Subject: [PATCH] regulator: add support for SY8106A regulator
SY8106A is an I2C attached single output regulator made by Silergy Corp,
which is used on several Allwinner H3/H5 SBCs to control the power
supply of the ARM cores.
Add a driver for it.
Signed-off-by: Ondrej Jirman <megous@megous.com>
[Icenowy: Change commit message, remove enable/disable code, add default
ramp_delay, add comment for go bit, add code for fixed mode voltage]
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
MAINTAINERS | 6 +
drivers/regulator/Kconfig | 7 ++
drivers/regulator/Makefile | 2 +-
drivers/regulator/sy8106a-regulator.c | 167 ++++++++++++++++++++++++++
4 files changed, 181 insertions(+), 1 deletion(-)
create mode 100644 drivers/regulator/sy8106a-regulator.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 0a1410d5a621..971300930067 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13461,6 +13461,12 @@ S: Supported
F: net/switchdev/
F: include/net/switchdev.h
+SY8106A REGULATOR DRIVER
+M: Icenowy Zheng <icenowy@aosc.io>
+S: Maintained
+F: drivers/regulator/sy8106a-regulator.c
+F: Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
+
SYNC FILE FRAMEWORK
M: Sumit Semwal <sumit.semwal@linaro.org>
R: Gustavo Padovan <gustavo@padovan.org>
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 097f61784a7d..4efae3b7e746 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -801,6 +801,13 @@ config REGULATOR_STW481X_VMMC
This driver supports the internal VMMC regulator in the STw481x
PMIC chips.
+config REGULATOR_SY8106A
+ tristate "Silergy SY8106A regulator"
+ depends on I2C && (OF || COMPILE_TEST)
+ select REGMAP_I2C
+ help
+ This driver supports SY8106A single output regulator.
+
config REGULATOR_TPS51632
tristate "TI TPS51632 Power Regulator"
depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 590674fbecd7..d81fb02bd6e9 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -100,6 +100,7 @@ obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
+obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
@@ -125,5 +126,4 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
-
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c
new file mode 100644
index 000000000000..65fbd1f0b612
--- /dev/null
+++ b/drivers/regulator/sy8106a-regulator.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// sy8106a-regulator.c - Regulator device driver for SY8106A
+//
+// Copyright (C) 2016 Ond??ej Jirman <megous@megous.com>
+// Copyright (c) 2017-2018 Icenowy Zheng <icenowy@aosc.io>
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SY8106A_REG_VOUT1_SEL 0x01
+#define SY8106A_REG_VOUT_COM 0x02
+#define SY8106A_REG_VOUT1_SEL_MASK 0x7f
+#define SY8106A_DISABLE_REG BIT(0)
+/*
+ * The I2C controlled voltage will only work when this bit is set; otherwise
+ * it will behave like a fixed regulator.
+ */
+#define SY8106A_GO_BIT BIT(7)
+
+struct sy8106a {
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ u32 fixed_voltage;
+};
+
+static const struct regmap_config sy8106a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static const struct regulator_ops sy8106a_ops = {
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ /* Enabling/disabling the regulator is not yet implemented */
+};
+
+/* Default limits measured in millivolts */
+#define SY8106A_MIN_MV 680
+#define SY8106A_MAX_MV 1950
+#define SY8106A_STEP_MV 10
+
+static const struct regulator_desc sy8106a_reg = {
+ .name = "SY8106A",
+ .id = 0,
+ .ops = &sy8106a_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1,
+ .min_uV = (SY8106A_MIN_MV * 1000),
+ .uV_step = (SY8106A_STEP_MV * 1000),
+ .vsel_reg = SY8106A_REG_VOUT1_SEL,
+ .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK,
+ /*
+ * This ramp_delay is a conservative default value which works on
+ * H3/H5 boards VDD-CPUX situations.
+ */
+ .ramp_delay = 200,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * I2C driver interface functions
+ */
+static int sy8106a_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct sy8106a *chip;
+ struct device *dev = &i2c->dev;
+ struct regulator_dev *rdev = NULL;
+ struct regulator_config config = { };
+ unsigned int reg, vsel;
+ int error;
+
+ chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ error = of_property_read_u32(dev->of_node, "silergy,fixed-microvolt",
+ &chip->fixed_voltage);
+ if (error)
+ return error;
+
+ if (chip->fixed_voltage < SY8106A_MIN_MV * 1000 ||
+ chip->fixed_voltage > SY8106A_MAX_MV * 1000)
+ return -EINVAL;
+
+ chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ error = PTR_ERR(chip->regmap);
+ dev_err(dev, "Failed to allocate register map: %d\n", error);
+ return error;
+ }
+
+ config.dev = &i2c->dev;
+ config.regmap = chip->regmap;
+ config.driver_data = chip;
+
+ config.of_node = dev->of_node;
+ config.init_data = of_get_regulator_init_data(dev, dev->of_node,
+ &sy8106a_reg);
+
+ if (!config.init_data)
+ return -ENOMEM;
+
+ /* Ensure GO_BIT is enabled when probing */
+ error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, ®);
+ if (error)
+ return error;
+
+ if (!(reg & SY8106A_GO_BIT)) {
+ vsel = (chip->fixed_voltage / 1000 - SY8106A_MIN_MV) /
+ SY8106A_STEP_MV;
+
+ error = regmap_write(chip->regmap, SY8106A_REG_VOUT1_SEL,
+ vsel | SY8106A_GO_BIT);
+ if (error)
+ return error;
+ }
+
+ /* Probe regulator */
+ rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config);
+ if (IS_ERR(rdev)) {
+ error = PTR_ERR(rdev);
+ dev_err(&i2c->dev, "Failed to register SY8106A regulator: %d\n", error);
+ return error;
+ }
+
+ chip->rdev = rdev;
+
+ i2c_set_clientdata(i2c, chip);
+
+ return 0;
+}
+
+static const struct of_device_id sy8106a_i2c_of_match[] = {
+ { .compatible = "silergy,sy8106a" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match);
+
+static const struct i2c_device_id sy8106a_i2c_id[] = {
+ { "sy8106a", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);
+
+static struct i2c_driver sy8106a_regulator_driver = {
+ .driver = {
+ .name = "sy8106a",
+ .of_match_table = of_match_ptr(sy8106a_i2c_of_match),
+ },
+ .probe = sy8106a_i2c_probe,
+ .id_table = sy8106a_i2c_id,
+};
+
+module_i2c_driver(sy8106a_regulator_driver);
+
+MODULE_AUTHOR("Ond??ej Jirman <megous@megous.com>");
+MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
+MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
+MODULE_LICENSE("GPL");
--
2.17.0
^ permalink raw reply related
* Applied "ASoC: fix return value check in mt6351_codec_driver_probe()" to the asoc tree
From: Mark Brown @ 2018-05-09 9:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525657185-73163-1-git-send-email-weiyongjun1@huawei.com>
The patch
ASoC: fix return value check in mt6351_codec_driver_probe()
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From aaa730ca3f88f535dc12e2f0ff575f70f516841b Mon Sep 17 00:00:00 2001
From: Wei Yongjun <weiyongjun1@huawei.com>
Date: Mon, 7 May 2018 01:39:45 +0000
Subject: [PATCH] ASoC: fix return value check in mt6351_codec_driver_probe()
In case of error, the function dev_get_regmap() returns NULL pointer not
ERR_PTR(). The IS_ERR() test in the return value check should be
replaced with NULL test.
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/codecs/mt6351.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c
index e739f078fec5..f73dcd753584 100644
--- a/sound/soc/codecs/mt6351.c
+++ b/sound/soc/codecs/mt6351.c
@@ -1472,8 +1472,8 @@ static int mt6351_codec_driver_probe(struct platform_device *pdev)
priv->dev = &pdev->dev;
priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
+ if (!priv->regmap)
+ return -ENODEV;
dev_dbg(priv->dev, "%s(), dev name %s\n",
__func__, dev_name(&pdev->dev));
--
2.17.0
^ permalink raw reply related
* Applied "ASoC: uniphier: evea: use DAPM to change source of line-in" to the asoc tree
From: Mark Brown @ 2018-05-09 9:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508084509.21616-1-suzuki.katsuhiro@socionext.com>
The patch
ASoC: uniphier: evea: use DAPM to change source of line-in
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From e5ba319882d78030b054dee4eeaf758340b2756f Mon Sep 17 00:00:00 2001
From: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Date: Tue, 8 May 2018 17:45:09 +0900
Subject: [PATCH] ASoC: uniphier: evea: use DAPM to change source of line-in
This patch replaces mixer switch to DAPM one for changing audio source
of line-in.
Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/uniphier/evea.c | 55 +++++++++++++++++++++++----------------
1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c
index 73fd6730095c..f9c10165fbc1 100644
--- a/sound/soc/uniphier/evea.c
+++ b/sound/soc/uniphier/evea.c
@@ -54,8 +54,21 @@ struct evea_priv {
int switch_hp;
};
+static const char * const linsw1_sel1_text[] = {
+ "LIN1", "LIN2", "LIN3"
+};
+
+static SOC_ENUM_SINGLE_DECL(linsw1_sel1_enum,
+ ALINSW1, ALINSW1_SEL1_SHIFT,
+ linsw1_sel1_text);
+
+static const struct snd_kcontrol_new linesw1_mux[] = {
+ SOC_DAPM_ENUM("Line In 1 Source", linsw1_sel1_enum),
+};
+
static const struct snd_soc_dapm_widget evea_widgets[] = {
- SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_MUX("Line In 1 Mux", SND_SOC_NOPM, 0, 0, linesw1_mux),
SND_SOC_DAPM_INPUT("LIN1_LP"),
SND_SOC_DAPM_INPUT("LIN1_RP"),
SND_SOC_DAPM_INPUT("LIN2_LP"),
@@ -63,7 +76,9 @@ static const struct snd_soc_dapm_widget evea_widgets[] = {
SND_SOC_DAPM_INPUT("LIN3_LP"),
SND_SOC_DAPM_INPUT("LIN3_RP"),
- SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC HP", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC LO1", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC LO2", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUTPUT("HP1_L"),
SND_SOC_DAPM_OUTPUT("HP1_R"),
SND_SOC_DAPM_OUTPUT("LO2_L"),
@@ -71,17 +86,22 @@ static const struct snd_soc_dapm_widget evea_widgets[] = {
};
static const struct snd_soc_dapm_route evea_routes[] = {
- { "ADC", NULL, "LIN1_LP" },
- { "ADC", NULL, "LIN1_RP" },
- { "ADC", NULL, "LIN2_LP" },
- { "ADC", NULL, "LIN2_RP" },
- { "ADC", NULL, "LIN3_LP" },
- { "ADC", NULL, "LIN3_RP" },
-
- { "HP1_L", NULL, "DAC" },
- { "HP1_R", NULL, "DAC" },
- { "LO2_L", NULL, "DAC" },
- { "LO2_R", NULL, "DAC" },
+ { "Line In 1", NULL, "ADC" },
+ { "ADC", NULL, "Line In 1 Mux" },
+ { "Line In 1 Mux", "LIN1", "LIN1_LP" },
+ { "Line In 1 Mux", "LIN1", "LIN1_RP" },
+ { "Line In 1 Mux", "LIN2", "LIN2_LP" },
+ { "Line In 1 Mux", "LIN2", "LIN2_RP" },
+ { "Line In 1 Mux", "LIN3", "LIN3_LP" },
+ { "Line In 1 Mux", "LIN3", "LIN3_RP" },
+
+ { "DAC HP", NULL, "Headphone 1" },
+ { "DAC LO1", NULL, "Line Out 1" },
+ { "DAC LO2", NULL, "Line Out 2" },
+ { "HP1_L", NULL, "DAC HP" },
+ { "HP1_R", NULL, "DAC HP" },
+ { "LO2_L", NULL, "DAC LO2" },
+ { "LO2_R", NULL, "DAC LO2" },
};
static void evea_set_power_state_on(struct evea_priv *evea)
@@ -280,16 +300,7 @@ static int evea_set_switch_hp(struct snd_kcontrol *kcontrol,
return evea_update_switch_hp(evea);
}
-static const char * const linsw1_sel1_text[] = {
- "LIN1", "LIN2", "LIN3"
-};
-
-static SOC_ENUM_SINGLE_DECL(linsw1_sel1_enum,
- ALINSW1, ALINSW1_SEL1_SHIFT,
- linsw1_sel1_text);
-
static const struct snd_kcontrol_new evea_controls[] = {
- SOC_ENUM("Line Capture Source", linsw1_sel1_enum),
SOC_SINGLE_BOOL_EXT("Line Capture Switch", 0,
evea_get_switch_lin, evea_set_switch_lin),
SOC_SINGLE_BOOL_EXT("Line Playback Switch", 0,
--
2.17.0
^ permalink raw reply related
* [PATCH v6 11/15] KVM: arm64: Save host SVE context as appropriate
From: Dave Martin @ 2018-05-09 9:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <606acf08-5af7-8045-221d-73737e730c3c@arm.com>
On Wed, May 09, 2018 at 09:50:26AM +0100, Marc Zyngier wrote:
> On 08/05/18 17:44, Dave Martin wrote:
> > This patch adds SVE context saving to the hyp FPSIMD context switch
> > path. This means that it is no longer necessary to save the host
> > SVE state in advance of entering the guest, when in use.
> >
> > In order to avoid adding pointless complexity to the code, VHE is
> > assumed if SVE is in use. VHE is an architectural prerequisite for
> > SVE, so there is no good reason to turn CONFIG_ARM64_VHE off in
> > kernels that support both SVE and KVM.
> >
> > Historically, software models exist that can expose the
> > architecturally invalid configuration of SVE without VHE, so if
> > this situation is detected this patch warns and refuses to create a
> > VM. Doing this check at VM creation time avoids race issues
> > between KVM and SVE initialisation.
>
> I don't think the commit log now reflects the code, since we bail out at
> init time and disable KVM altogether.
Will fix to say that we simply disable KVM completely at kvm_init() time
in this case.
[...]
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
[...]
> > @@ -337,8 +341,22 @@ void __hyp_text __hyp_switch_fpsimd(u64 esr __always_unused,
> >
> > isb();
> >
> > - if (vcpu->arch.host_fpsimd_state) {
> > - __fpsimd_save_state(vcpu->arch.host_fpsimd_state);
> > + if (host_fpsimd) {
> > + /*
> > + * In the SVE case, VHE is assumed: it is enforced by
> > + * Kconfig and kvm_arch_init_vm().
>
> Nit: this is now kvm_arch_init().
Will fix.
[...]
> Otherwise:
>
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Thanks
---Dave
^ permalink raw reply
* [RFC PATCH] driver core: make deferring probe forever optional
From: Mark Brown @ 2018-05-09 9:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507223438.GB14924@minitux>
On Mon, May 07, 2018 at 03:34:38PM -0700, Bjorn Andersson wrote:
> And is this really a problem that does not exists in the ACPI world?
Sort of, in that on ACPI systems all devices are expected to live in
glorious isolation and anything they need transparently configured by
the firmware with any information about clock speeds or whatever coming
from proprietary/device specific properties (though that's severely
frowned upon) or the apparently idiomatic technique of hardcoding based
on DMI data which has some scalability issues. This works great for
systems intended to work in the ACPI model but is not entirely
successful once you get outside of that.
Some of the embedded ACPI people have been importing bits of DT
wholesale into ACPI, for those bits obviously all the DT issues get
imported too.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180509/63308370/attachment.sig>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox