* [PATCH v2 07/11] drm/rockchip/dsi: fix mipi display can't found at init time
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
From: Mark Yao <mark.yao@rock-chips.com>
The problem is that:
mipi panel probe request mipi_dsi_host_register.
mipi host attach is call from panel device, so the defer function
always can't works.
So at the first bind time, always can't found mipi panel.
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 57 +++++++++++++++++++++++-----------
1 file changed, 39 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 5e3f031..4ec82f6 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -551,11 +551,9 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
dsi->panel = of_drm_find_panel(device->dev.of_node);
if (!dsi->panel) {
DRM_ERROR("failed to find panel\n");
- return -EPROBE_DEFER;
+ return -ENODEV;
}
- drm_panel_attach(dsi->panel, &dsi->connector);
-
return 0;
}
@@ -567,6 +565,7 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
if (dsi->panel)
drm_panel_detach(dsi->panel);
+ dsi->panel = NULL;
return 0;
}
@@ -1048,6 +1047,8 @@ static int dw_mipi_dsi_register(struct drm_device *drm,
&dw_mipi_dsi_atomic_connector_funcs,
DRM_MODE_CONNECTOR_DSI);
+ drm_panel_attach(dsi->panel, &dsi->connector);
+
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
@@ -1097,23 +1098,17 @@ MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
void *data)
{
- const struct of_device_id *of_id =
- of_match_device(dw_mipi_dsi_dt_ids, dev);
- const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = data;
- struct dw_mipi_dsi *dsi;
+ struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
struct resource *res;
int ret;
- dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
- if (!dsi)
- return -ENOMEM;
-
- dsi->dev = dev;
- dsi->pdata = pdata;
dsi->dpms_mode = DRM_MODE_DPMS_OFF;
+ if (!dsi->panel)
+ return -EPROBE_DEFER;
+
ret = rockchip_mipi_parse_dt(dsi);
if (ret)
return ret;
@@ -1160,9 +1155,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
pm_runtime_enable(dev);
- dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
- dsi->dsi_host.dev = dev;
- return mipi_dsi_host_register(&dsi->dsi_host);
+ return 0;
err_pllref:
clk_disable_unprepare(dsi->pllref_clk);
@@ -1174,7 +1167,6 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
{
struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
- mipi_dsi_host_unregister(&dsi->dsi_host);
pm_runtime_disable(dev);
clk_disable_unprepare(dsi->pllref_clk);
}
@@ -1186,11 +1178,40 @@ static const struct component_ops dw_mipi_dsi_ops = {
static int dw_mipi_dsi_probe(struct platform_device *pdev)
{
- return component_add(&pdev->dev, &dw_mipi_dsi_ops);
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id =
+ of_match_device(dw_mipi_dsi_dt_ids, dev);
+ const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
+ struct dw_mipi_dsi *dsi;
+ int ret;
+
+ dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
+ if (!dsi)
+ return -ENOMEM;
+
+ dsi->dev = dev;
+ dsi->pdata = pdata;
+ dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
+ dsi->dsi_host.dev = &pdev->dev;
+
+ ret = mipi_dsi_host_register(&dsi->dsi_host);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, dsi);
+ ret = component_add(&pdev->dev, &dw_mipi_dsi_ops);
+ if (ret)
+ mipi_dsi_host_unregister(&dsi->dsi_host);
+
+ return ret;
}
static int dw_mipi_dsi_remove(struct platform_device *pdev)
{
+ struct dw_mipi_dsi *dsi = dev_get_drvdata(&pdev->dev);
+
+ if (dsi)
+ mipi_dsi_host_unregister(&dsi->dsi_host);
component_del(&pdev->dev, &dw_mipi_dsi_ops);
return 0;
}
--
2.6.3
^ permalink raw reply related
* [PATCH v2 06/11] drm/rockchip/dsi: return probe defer if attach panel failed
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
From: Mark Yao <mark.yao@rock-chips.com>
Return -EINVAL would cause mipi dsi bad behavior, probe defer
to ensure mipi find the correct mode,
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index d2a3efb..5e3f031 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -549,10 +549,14 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
dsi->channel = device->channel;
dsi->format = device->format;
dsi->panel = of_drm_find_panel(device->dev.of_node);
- if (dsi->panel)
- return drm_panel_attach(dsi->panel, &dsi->connector);
+ if (!dsi->panel) {
+ DRM_ERROR("failed to find panel\n");
+ return -EPROBE_DEFER;
+ }
- return -EINVAL;
+ drm_panel_attach(dsi->panel, &dsi->connector);
+
+ return 0;
}
static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
@@ -560,7 +564,8 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
{
struct dw_mipi_dsi *dsi = host_to_dsi(host);
- drm_panel_detach(dsi->panel);
+ if (dsi->panel)
+ drm_panel_detach(dsi->panel);
return 0;
}
--
2.6.3
^ permalink raw reply related
* [PATCH v2 05/11] drm/rockchip/dsi: add dw-mipi power domain support
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
Reference the power domain incase dw-mipi power down when
in use.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 8f8d48a..d2a3efb 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -12,6 +12,7 @@
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <drm/drm_atomic_helper.h>
@@ -291,6 +292,7 @@ struct dw_mipi_dsi {
struct clk *pclk;
struct clk *phy_cfg_clk;
+ int dpms_mode;
unsigned int lane_mbps; /* per lane */
u32 channel;
u32 lanes;
@@ -842,6 +844,9 @@ static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder,
struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
int ret;
+ if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
+ return;
+
dsi->mode = adjusted_mode;
ret = dw_mipi_dsi_get_lane_bps(dsi);
@@ -853,6 +858,8 @@ static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder,
return;
}
+ pm_runtime_get_sync(dsi->dev);
+
dw_mipi_dsi_init(dsi);
dw_mipi_dsi_dpi_config(dsi, mode);
dw_mipi_dsi_packet_handler_config(dsi);
@@ -874,6 +881,9 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
{
struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
+ if (dsi->dpms_mode != DRM_MODE_DPMS_ON)
+ return;
+
drm_panel_disable(dsi->panel);
if (clk_prepare_enable(dsi->pclk)) {
@@ -893,7 +903,9 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
dw_mipi_dsi_disable(dsi);
+ pm_runtime_put(dsi->dev);
clk_disable_unprepare(dsi->pclk);
+ dsi->dpms_mode = DRM_MODE_DPMS_OFF;
}
static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
@@ -927,6 +939,7 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
+ dsi->dpms_mode = DRM_MODE_DPMS_ON;
}
static int
@@ -1094,6 +1107,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
dsi->dev = dev;
dsi->pdata = pdata;
+ dsi->dpms_mode = DRM_MODE_DPMS_OFF;
ret = rockchip_mipi_parse_dt(dsi);
if (ret)
@@ -1139,6 +1153,8 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
dev_set_drvdata(dev, dsi);
+ pm_runtime_enable(dev);
+
dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
dsi->dsi_host.dev = dev;
return mipi_dsi_host_register(&dsi->dsi_host);
@@ -1154,6 +1170,7 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
mipi_dsi_host_unregister(&dsi->dsi_host);
+ pm_runtime_disable(dev);
clk_disable_unprepare(dsi->pllref_clk);
}
--
2.6.3
^ permalink raw reply related
* [PATCH v2 04/11] dt-bindings: add power domain node for dw-mipi-rockchip
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Acked-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
index 0f82568..188f6f7 100644
--- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
@@ -15,6 +15,9 @@ Required properties:
- ports: contain a port node with endpoint definitions as defined in [2].
For vopb,set the reg = <0> and set the reg = <1> for vopl.
+Optional properties:
+- power-domains: a phandle to mipi dsi power domain node.
+
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/media/video-interfaces.txt
--
2.6.3
^ permalink raw reply related
* [PATCH v2 03/11] drm/rockchip/dsi: remove mode_valid function
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
The MIPI DSI do not need check the validity of resolution, the max
resolution should depend VOP. Hence, remove rk3288_mipi_dsi_mode_valid
here.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 39 ----------------------------------
1 file changed, 39 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 04fd595..8f8d48a 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -276,8 +276,6 @@ struct dw_mipi_dsi_plat_data {
u32 grf_dsi0_mode;
u32 grf_dsi0_mode_reg;
unsigned int max_data_lanes;
- enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);
};
struct dw_mipi_dsi {
@@ -978,23 +976,8 @@ static int dw_mipi_dsi_connector_get_modes(struct drm_connector *connector)
return drm_panel_get_modes(dsi->panel);
}
-static enum drm_mode_status dw_mipi_dsi_mode_valid(
- struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- struct dw_mipi_dsi *dsi = con_to_dsi(connector);
-
- enum drm_mode_status mode_status = MODE_OK;
-
- if (dsi->pdata->mode_valid)
- mode_status = dsi->pdata->mode_valid(connector, mode);
-
- return mode_status;
-}
-
static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = {
.get_modes = dw_mipi_dsi_connector_get_modes,
- .mode_valid = dw_mipi_dsi_mode_valid,
};
static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
@@ -1065,33 +1048,11 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
return 0;
}
-static enum drm_mode_status rk3288_mipi_dsi_mode_valid(
- struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- /*
- * The VID_PKT_SIZE field in the DSI_VID_PKT_CFG
- * register is 11-bit.
- */
- if (mode->hdisplay > 0x7ff)
- return MODE_BAD_HVALUE;
-
- /*
- * The V_ACTIVE_LINES field in the DSI_VTIMING_CFG
- * register is 11-bit.
- */
- if (mode->vdisplay > 0x7ff)
- return MODE_BAD_VVALUE;
-
- return MODE_OK;
-}
-
static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
.dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT,
.dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
.grf_switch_reg = RK3288_GRF_SOC_CON6,
.max_data_lanes = 4,
- .mode_valid = rk3288_mipi_dsi_mode_valid,
};
static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
--
2.6.3
^ permalink raw reply related
* [PATCH v2 02/11] drm/rockchip/dsi: dw-mipi: support RK3399 mipi dsi
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
The vopb/vopl switch register of RK3399 mipi is different from RK3288,
the default setting for mipi dsi mode is different too, so add a
of_device_id structure to distinguish them, and make sure set the
correct mode before mipi phy init.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 101 ++++++++++++++++++++++++---------
1 file changed, 74 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index d9aa382..04fd595 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -28,9 +28,17 @@
#define DRIVER_NAME "dw-mipi-dsi"
-#define GRF_SOC_CON6 0x025c
-#define DSI0_SEL_VOP_LIT (1 << 6)
-#define DSI1_SEL_VOP_LIT (1 << 9)
+#define RK3288_GRF_SOC_CON6 0x025c
+#define RK3288_DSI0_SEL_VOP_LIT BIT(6)
+#define RK3288_DSI1_SEL_VOP_LIT BIT(9)
+
+#define RK3399_GRF_SOC_CON19 0x6250
+#define RK3399_DSI0_SEL_VOP_LIT BIT(0)
+#define RK3399_DSI1_SEL_VOP_LIT BIT(4)
+
+/* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
+#define RK3399_GRF_SOC_CON22 0x6258
+#define RK3399_GRF_DSI_MODE 0xffff0000
#define DSI_VERSION 0x00
#define DSI_PWR_UP 0x04
@@ -147,7 +155,6 @@
#define LPRX_TO_CNT(p) ((p) & 0xffff)
#define DSI_BTA_TO_CNT 0x8c
-
#define DSI_LPCLK_CTRL 0x94
#define AUTO_CLKLANE_CTRL BIT(1)
#define PHY_TXREQUESTCLKHS BIT(0)
@@ -213,11 +220,11 @@
#define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
-#define INPUT_DIVIDER(val) ((val - 1) & 0x7f)
+#define INPUT_DIVIDER(val) (((val) - 1) & 0x7f)
#define LOW_PROGRAM_EN 0
#define HIGH_PROGRAM_EN BIT(7)
-#define LOOP_DIV_LOW_SEL(val) ((val - 1) & 0x1f)
-#define LOOP_DIV_HIGH_SEL(val) (((val - 1) >> 5) & 0x1f)
+#define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
+#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0x1f)
#define PLL_LOOP_DIV_EN BIT(5)
#define PLL_INPUT_DIV_EN BIT(4)
@@ -263,6 +270,11 @@ enum {
};
struct dw_mipi_dsi_plat_data {
+ u32 dsi0_en_bit;
+ u32 dsi1_en_bit;
+ u32 grf_switch_reg;
+ u32 grf_dsi0_mode;
+ u32 grf_dsi0_mode_reg;
unsigned int max_data_lanes;
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
@@ -279,6 +291,7 @@ struct dw_mipi_dsi {
struct clk *pllref_clk;
struct clk *pclk;
+ struct clk *phy_cfg_clk;
unsigned int lane_mbps; /* per lane */
u32 channel;
@@ -353,6 +366,7 @@ static inline struct dw_mipi_dsi *encoder_to_dsi(struct drm_encoder *encoder)
{
return container_of(encoder, struct dw_mipi_dsi, encoder);
}
+
static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val)
{
writel(val, dsi->base + reg);
@@ -364,7 +378,7 @@ static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg)
}
static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 test_code,
- u8 test_data)
+ u8 test_data)
{
/*
* With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
@@ -400,6 +414,14 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
dsi_write(dsi, DSI_PWR_UP, POWERUP);
+ if (!IS_ERR(dsi->phy_cfg_clk)) {
+ ret = clk_prepare_enable(dsi->phy_cfg_clk);
+ if (ret) {
+ dev_err(dsi->dev, "Failed to enable phy_cfg_clk\n");
+ return ret;
+ }
+ }
+
dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
VCO_RANGE_CON_SEL(vco) |
VCO_IN_CAP_CON_LOW |
@@ -439,22 +461,23 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
-
ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS,
val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US);
if (ret < 0) {
dev_err(dsi->dev, "failed to wait for phy lock state\n");
- return ret;
+ goto phy_init_end;
}
ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS,
val, val & STOP_STATE_CLK_LANE, 1000,
PHY_STATUS_TIMEOUT_US);
- if (ret < 0) {
+ if (ret < 0)
dev_err(dsi->dev,
"failed to wait for phy clk lane stop state\n");
- return ret;
- }
+
+phy_init_end:
+ if (!IS_ERR(dsi->phy_cfg_clk))
+ clk_disable_unprepare(dsi->phy_cfg_clk);
return ret;
}
@@ -512,7 +535,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
if (device->lanes > dsi->pdata->max_data_lanes) {
dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
- device->lanes);
+ device->lanes);
return -EINVAL;
}
@@ -815,8 +838,8 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
}
static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
int ret;
@@ -878,6 +901,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
{
struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
+ const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
u32 val;
@@ -886,6 +910,10 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
return;
}
+ if (pdata->grf_dsi0_mode_reg)
+ regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
+ pdata->grf_dsi0_mode);
+
dw_mipi_dsi_phy_init(dsi);
dw_mipi_dsi_wait_for_two_frames(dsi);
@@ -895,11 +923,11 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
clk_disable_unprepare(dsi->pclk);
if (mux)
- val = DSI0_SEL_VOP_LIT | (DSI0_SEL_VOP_LIT << 16);
+ val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
else
- val = DSI0_SEL_VOP_LIT << 16;
+ val = pdata->dsi0_en_bit << 16;
- regmap_write(dsi->grf_regmap, GRF_SOC_CON6, val);
+ regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
}
@@ -931,7 +959,7 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
return 0;
}
-static struct drm_encoder_helper_funcs
+static const struct drm_encoder_helper_funcs
dw_mipi_dsi_encoder_helper_funcs = {
.commit = dw_mipi_dsi_encoder_commit,
.mode_set = dw_mipi_dsi_encoder_mode_set,
@@ -939,7 +967,7 @@ dw_mipi_dsi_encoder_helper_funcs = {
.atomic_check = dw_mipi_dsi_encoder_atomic_check,
};
-static struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
+static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -975,7 +1003,7 @@ static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
+static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = dw_mipi_dsi_drm_connector_destroy,
@@ -985,7 +1013,7 @@ static struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
};
static int dw_mipi_dsi_register(struct drm_device *drm,
- struct dw_mipi_dsi *dsi)
+ struct dw_mipi_dsi *dsi)
{
struct drm_encoder *encoder = &dsi->encoder;
struct drm_connector *connector = &dsi->connector;
@@ -1006,14 +1034,14 @@ static int dw_mipi_dsi_register(struct drm_device *drm,
drm_encoder_helper_add(&dsi->encoder,
&dw_mipi_dsi_encoder_helper_funcs);
ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs,
- DRM_MODE_ENCODER_DSI, NULL);
+ DRM_MODE_ENCODER_DSI, NULL);
if (ret) {
dev_err(dev, "Failed to initialize encoder with drm\n");
return ret;
}
drm_connector_helper_add(connector,
- &dw_mipi_dsi_connector_helper_funcs);
+ &dw_mipi_dsi_connector_helper_funcs);
drm_connector_init(drm, &dsi->connector,
&dw_mipi_dsi_atomic_connector_funcs,
@@ -1059,21 +1087,36 @@ static enum drm_mode_status rk3288_mipi_dsi_mode_valid(
}
static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
+ .dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT,
+ .dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
+ .grf_switch_reg = RK3288_GRF_SOC_CON6,
.max_data_lanes = 4,
.mode_valid = rk3288_mipi_dsi_mode_valid,
};
+static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
+ .dsi0_en_bit = RK3399_DSI0_SEL_VOP_LIT,
+ .dsi1_en_bit = RK3399_DSI1_SEL_VOP_LIT,
+ .grf_switch_reg = RK3399_GRF_SOC_CON19,
+ .grf_dsi0_mode = RK3399_GRF_DSI_MODE,
+ .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
+ .max_data_lanes = 4,
+};
+
static const struct of_device_id dw_mipi_dsi_dt_ids[] = {
{
.compatible = "rockchip,rk3288-mipi-dsi",
.data = &rk3288_mipi_dsi_drv_data,
+ }, {
+ .compatible = "rockchip,rk3399-mipi-dsi",
+ .data = &rk3399_mipi_dsi_drv_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
- void *data)
+ void *data)
{
const struct of_device_id *of_id =
of_match_device(dw_mipi_dsi_dt_ids, dev);
@@ -1117,6 +1160,10 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
return ret;
}
+ dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
+ if (IS_ERR(dsi->phy_cfg_clk))
+ dev_dbg(dev, "have not phy_cfg_clk\n");
+
ret = clk_prepare_enable(dsi->pllref_clk);
if (ret) {
dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
@@ -1141,7 +1188,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
}
static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
- void *data)
+ void *data)
{
struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
--
2.6.3
^ permalink raw reply related
* [PATCH v2 01/11] dt-bindings: add rk3399 support for dw-mipi-rockchip
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
The dw-mipi-dsi of rk3399 is almost the same as rk3288, the rk3399 has
additional phy config clock.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---
.../devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
index 1753f0c..0f82568 100644
--- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
@@ -5,10 +5,12 @@ Required properties:
- #address-cells: Should be <1>.
- #size-cells: Should be <0>.
- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi".
+ "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi".
- reg: Represent the physical address range of the controller.
- interrupts: Represent the controller's interrupt to the CPU(s).
- clocks, clock-names: Phandles to the controller's pll reference
- clock(ref) and APB clock(pclk), as described in [1].
+ clock(ref) and APB clock(pclk). For RK3399, a phy config clock
+ (phy_cfg) is additional required. As described in [1].
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
- ports: contain a port node with endpoint definitions as defined in [2].
For vopb,set the reg = <0> and set the reg = <1> for vopl.
--
2.6.3
^ permalink raw reply related
* [PATCH v2 0/11] Rockchip dw-mipi-dsi driver
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
Hi all
This patch serial is for RK3399 MIPI DSI. The MIPI DSI controller of
RK3399 is almost the same as RK3288, except a little bit of difference
in phy clock controlling and port id selection register.
And these patches also fixes some driver bugs; add the power domain
support.
they have been tested on rk3399 and rk3288 evb board.
Chris Zhong (7):
dt-bindings: add rk3399 support for dw-mipi-rockchip
drm/rockchip/dsi: dw-mipi: support RK3399 mipi dsi
drm/rockchip/dsi: remove mode_valid function
dt-bindings: add power domain node for dw-mipi-rockchip
drm/rockchip/dsi: add dw-mipi power domain support
drm/rockchip/dsi: fix phy clk lane stop state timeout
drm/rockchip/dsi: fix insufficient bandwidth of some panel
Mark Yao (2):
drm/rockchip/dsi: return probe defer if attach panel failed
drm/rockchip/dsi: fix mipi display can't found at init time
xubilv (2):
drm/rockchip/dsi: fix the issue can not send commands
drm/rockchip/dsi: decrease the value of Ths-prepare
.../display/rockchip/dw_mipi_dsi_rockchip.txt | 7 +-
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 254 +++++++++++++--------
2 files changed, 163 insertions(+), 98 deletions(-)
--
2.6.3
^ permalink raw reply
* [PATCH 09/10] ARM: dts: da850: add the SATA node
From: Bartosz Golaszewski @ 2017-01-16 10:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4eb4ada8-1d2d-2fa1-7961-21da56ea0082@lechnology.com>
2017-01-13 20:36 GMT+01:00 David Lechner <david@lechnology.com>:
> On 01/13/2017 06:38 AM, Bartosz Golaszewski wrote:
>>
>> Add the SATA node to the da850 device tree.
>>
>> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>> ---
>> arch/arm/boot/dts/da850.dtsi | 6 ++++++
>> 1 file changed, 6 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
>> index 1f6a47d..f5086b1 100644
>> --- a/arch/arm/boot/dts/da850.dtsi
>> +++ b/arch/arm/boot/dts/da850.dtsi
>> @@ -427,6 +427,12 @@
>> phy-names = "usb-phy";
>> status = "disabled";
>> };
>> + sata: ahci at 0x218000 {
>
>
> 0x needs to be omitted.
>
> sata: ahci at 218000 {
>
Will fix in v2.
Thanks,
Bartosz Golaszewski
^ permalink raw reply
* [PATCH v1 3/3] reset: zx2967: add reset controller driver for ZTE's zx2967 family
From: Philipp Zabel @ 2017-01-16 9:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484377530-30635-3-git-send-email-baoyou.xie@linaro.org>
On Sat, 2017-01-14 at 15:05 +0800, Baoyou Xie wrote:
> This patch adds reset controller driver for ZTE's zx2967 family.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
> drivers/reset/Kconfig | 6 ++
> drivers/reset/Makefile | 1 +
> drivers/reset/reset-zx2967.c | 136 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 143 insertions(+)
> create mode 100644 drivers/reset/reset-zx2967.c
>
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index 172dc96..972d077 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -92,6 +92,12 @@ config RESET_ZYNQ
> help
> This enables the reset controller driver for Xilinx Zynq SoCs.
>
> +config RESET_ZX2967
> + bool "ZX2967 Reset Driver"
> + depends on ARCH_ZX || COMPILE_TEST
> + help
> + This enables the reset controller driver for ZTE zx2967 family.
> +
> source "drivers/reset/sti/Kconfig"
> source "drivers/reset/hisilicon/Kconfig"
> source "drivers/reset/tegra/Kconfig"
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 13b346e..807b77b 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -14,3 +14,4 @@ obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
> obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
> obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
> obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
> +obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o
> diff --git a/drivers/reset/reset-zx2967.c b/drivers/reset/reset-zx2967.c
> new file mode 100644
> index 0000000..63f9c41
> --- /dev/null
> +++ b/drivers/reset/reset-zx2967.c
> @@ -0,0 +1,136 @@
> +/*
> + * ZTE's zx2967 family thermal sensor driver
This description is incorrect.
> + *
> + * Copyright (C) 2017 ZTE Ltd.
> + *
> + * Author: Baoyou Xie <baoyou.xie@linaro.org>
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +
> +struct zx2967_reset {
> + void __iomem *reg_base;
> + spinlock_t lock;
> + struct reset_controller_dev rcdev;
> +};
> +
> +static int zx2967_reset_assert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct zx2967_reset *reset = NULL;
> + int bank = id / 32;
> + int offset = id % 32;
> + unsigned int reg;
> + unsigned long flags;
> +
> + reset = container_of(rcdev, struct zx2967_reset, rcdev);
> +
> + spin_lock_irqsave(&reset->lock, flags);
> +
> + reg = readl(reset->reg_base + (bank * 4));
> + writel(reg & ~BIT(offset), reset->reg_base + (bank * 4));
> + reg = readl(reset->reg_base + (bank * 4));
> +
> + spin_unlock_irqrestore(&reset->lock, flags);
> +
> + return 0;
> +}
> +
> +static int zx2967_reset_deassert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct zx2967_reset *reset = NULL;
> + int bank = id / 32;
> + int offset = id % 32;
> + unsigned int reg;
> + unsigned long flags;
> +
> + reset = container_of(rcdev, struct zx2967_reset, rcdev);
> +
> + spin_lock_irqsave(&reset->lock, flags);
> +
> + reg = readl(reset->reg_base + (bank * 4));
> + writel(reg | BIT(offset), reset->reg_base + (bank * 4));
> + reg = readl(reset->reg_base + (bank * 4));
> +
> + spin_unlock_irqrestore(&reset->lock, flags);
> +
> + return 0;
> +}
> +
> +static struct reset_control_ops zx2967_reset_ops = {
> + .assert = zx2967_reset_assert,
> + .deassert = zx2967_reset_deassert,
> +};
> +
> +static int zx2967_reset_probe(struct platform_device *pdev)
> +{
> + struct zx2967_reset *reset;
> + struct resource *res;
> +
> + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
> + if (!reset)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + reset->reg_base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(reset->reg_base))
> + return PTR_ERR(reset->reg_base);
> +
> + spin_lock_init(&reset->lock);
> +
> + reset->rcdev.owner = THIS_MODULE;
> + reset->rcdev.nr_resets = resource_size(res) * 8;
> + reset->rcdev.ops = &zx2967_reset_ops;
> + reset->rcdev.of_node = pdev->dev.of_node;
> +
> + dev_info(&pdev->dev, "reset controller cnt:%d",
> + reset->rcdev.nr_resets);
> +
> + return reset_controller_register(&reset->rcdev);
As Shawn suggested, use the devm_ variant here. It allows you to drop
the remove function below.
> +}
> +
> +static int zx2967_reset_remove(struct platform_device *pdev)
> +{
> + struct zx2967_reset *reset = platform_get_drvdata(pdev);
> +
> + reset_controller_unregister(&reset->rcdev);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id zx2967_reset_dt_ids[] = {
> + { .compatible = "zte,zx296718-reset", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, zx2967_reset_dt_ids);
> +
> +static struct platform_driver zx2967_reset_driver = {
> + .probe = zx2967_reset_probe,
> + .remove = zx2967_reset_remove,
> + .driver = {
> + .name = "zx2967-reset",
> + .of_match_table = zx2967_reset_dt_ids,
> + },
> +};
> +
> +static int __init zx2967_reset_init(void)
> +{
> + return platform_driver_register(&zx2967_reset_driver);
> +}
> +arch_initcall(zx2967_reset_init);
> +
> +static void __exit zx2967_reset_exit(void)
> +{
> + platform_driver_unregister(&zx2967_reset_driver);
> +}
> +module_exit(zx2967_reset_exit);
> +
> +MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
> +MODULE_DESCRIPTION("ZTE zx2967 Reset Controller Driver");
> +MODULE_LICENSE("GPL");
regards
Philipp
^ permalink raw reply
* [PATCH v1 1/3] dt: bindings: add documentation for zx2967 family reset controller
From: Philipp Zabel @ 2017-01-16 9:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484377530-30635-1-git-send-email-baoyou.xie@linaro.org>
Hi,
On Sat, 2017-01-14 at 15:05 +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zx2967 family
> reset controller.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
> .../devicetree/bindings/reset/zte,zx2967-reset.txt | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
>
> diff --git a/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt b/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
> new file mode 100644
> index 0000000..22d590e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
> @@ -0,0 +1,20 @@
> +ZTE zx2967 SoCs Reset Controller
> +=======================================
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +Required properties:
> +- compatible: should be one of the following.
> + * zte,zx296718-reset
> +- reg: physical base address of the controller and length of memory mapped
> + region.
> +- #reset-cells: must be 1.
> +
> +example:
> +
> + toprst: reset at 1461060 {
That node should be named reset-controller.
> + compatible = "zte,zx296718-reset";
> + reg = <0x01461060 0x8>;
> + #reset-cells = <1>;
> + };
regards
Philipp
^ permalink raw reply
* [PATCH RFC 2/2] ARM: nommu: remap exception base address to RAM
From: Vladimir Murzin @ 2017-01-16 9:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170115114750.GA5456@afzalpc>
Hi,
On 15/01/17 11:47, Afzal Mohammed wrote:
> Hi,
>
> On Sat, Jan 07, 2017 at 10:43:39PM +0530, Afzal Mohammed wrote:
>> On Tue, Dec 13, 2016 at 10:02:26AM +0000, Russell King - ARM Linux wrote:
>
>>> Also, if the region setup for the vectors was moved as well, it would
>>> then be possible to check the ID registers to determine whether this
>>> is supported, and make the decision where to locate the vectors base
>>> more dynamically.
>>
>> This would affect Cortex-R's, which is a bit concerning due to lack of
>> those platforms with me, let me try to get it right.
>
> QEMU too doesn't seem to provide a Cortex-R target
>
>> Seems translating __setup_mpu() altogether to C
>
> afaics, a kind of C translation is already present as
> mpu_setup_region() in arch/arm/mm/nommu.c that takes care of
> MPU_RAM_REGION only. And that seems to be a kind of redundant as it is
> also done in asm at __setup_mpu(). Git blames asm & C to consecutive
> commits, that makes me a little shaky about the conclusion on it being
> redundant.
>
It is not redundant. MPU setup is done it two steps. The first step done in
asm to enable caches, there only kernel image is covered; the second step takes
care on the whole RAM given via dt or "mem=" parameter.
I think other regions are kept there to avoid C side dancing in case of SMP.
>> & installing at a later, but suitable place might be better.
>
> But looks like enabling MPU can't be moved to C & that would
> necessitate keeping at least some portion of__setu_mpu() in asm.
>
> Instead, moving region setup only for vectors to C as Russell
> suggested at first would have to be done.
>
> A kind of diff at the end is in my mind, with additional changes to
> handle the similar during secondary cpu bringup too.
>
> Thinking of invoking mpu_setup() from secondary_start_kernel() in
> arch/arm/kernel/smp.c, with mpu_setup() being slightly modified to
> avoid storing region details again when invoked by secondary cpu's.
I have wip patches on reworking MPU setup code. The idea is to start using
mpu_rgn_info[] actively, so asm part for secondariness would just sync-up
content of that array. Additionally, it seems that we can reuse free MPU slots
to cover memory which is discarded due to MPU alignment restrictions...
>
> Vladimir, once changes are done after a revisit, i would need your
> help to test on Cortex-R.
I'm more than happy to help, but currently I have limited bandwidth, so if it
can wait till the next dev cycle I'd try to make MPU rework finished by that
time.
>
> As an aside, wasn't aware of the fact that Cortex-R supports SMP
> Linux, had thought that, of !MMU one's, only Blackfin & J2 had it.
>
>
>> Also !MMU Kernel could boot on 3 ARM v7-A platforms - AM335x Beagle
>> Bone (A8), AM437x IDK (A9) & Vybrid VF610 (on A5 core, note that it
>> has M4 core too)
>
> Talking about Cortex-M, AMx3's too have it, to be specific M3, but
> they are not Linux-able unlike the one in VF610.
>
Thanks!
Vladimir
> Regards
> afzal
>
> --->8---
>
> diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
> index e0565d73e49e..f8ac79b6136d 100644
> --- a/arch/arm/kernel/head-nommu.S
> +++ b/arch/arm/kernel/head-nommu.S
> @@ -249,20 +249,6 @@ ENTRY(__setup_mpu)
> setup_region r0, r5, r6, MPU_INSTR_SIDE @ 0x0, BG region, enabled
> 2: isb
>
> - /* Vectors region */
> - set_region_nr r0, #MPU_VECTORS_REGION
> - isb
> - /* Shared, inaccessible to PL0, rw PL1 */
> - mov r0, #CONFIG_VECTORS_BASE @ Cover from VECTORS_BASE
> - ldr r5,=(MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL)
> - /* Writing N to bits 5:1 (RSR_SZ) --> region size 2^N+1 */
> - mov r6, #(((2 * PAGE_SHIFT - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN)
> -
> - setup_region r0, r5, r6, MPU_DATA_SIDE @ VECTORS_BASE, PL0 NA, enabled
> - beq 3f @ Memory-map not unified
> - setup_region r0, r5, r6, MPU_INSTR_SIDE @ VECTORS_BASE, PL0 NA, enabled
> -3: isb
> -
> /* Enable the MPU */
> mrc p15, 0, r0, c1, c0, 0 @ Read SCTLR
> bic r0, r0, #CR_BR @ Disable the 'default mem-map'
> diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
> index e82056df0635..7fe8906322d5 100644
> --- a/arch/arm/mm/nommu.c
> +++ b/arch/arm/mm/nommu.c
> @@ -269,12 +269,19 @@ void __init mpu_setup(void)
> ilog2(memblock.memory.regions[0].size),
> MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
> if (region_err) {
> - panic("MPU region initialization failure! %d", region_err);
> + panic("MPU RAM region initialization failure! %d", region_err);
> } else {
> - pr_info("Using ARMv7 PMSA Compliant MPU. "
> - "Region independence: %s, Max regions: %d\n",
> - mpu_iside_independent() ? "Yes" : "No",
> - mpu_max_regions());
> + region_err = mpu_setup_region(MPU_VECTORS_REGION, vectors_base,
> + ilog2(memblock.memory.regions[0].size),
> + MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL);
> + if (region_err) {
> + panic("MPU VECTOR region initialization failure! %d",
> + region_err);
> + } else {
> + pr_info("Using ARMv7 PMSA Compliant MPU. "
> + "Region independence: %s, Max regions: %d\n",
> + mpu_iside_independent() ? "Yes" : "No",
> + mpu_max_regions());
> }
> }
> #else
>
^ permalink raw reply
* [PATCH 3/4] ARM64: dts: meson-gx-p23x-q20x: enable the Bluetooth module
From: Martin Blumenstingl @ 2017-01-16 9:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <042e2824-0772-cf27-ffa5-4c3b2af7c92b@suse.de>
On Mon, Jan 16, 2017 at 1:47 AM, Andreas F?rber <afaerber@suse.de> wrote:
> Am 15.01.2017 um 23:32 schrieb Martin Blumenstingl:
>> This takes the Bluetooth module out of reset (the reset line is
>> connected to GPIOX_17) and enables uart_A which is used to configure the
>> module.
>> This is identical for all boards which inherit meson-gx-p23x-q20x:
>> - GXL S905D P230
>> - GXL S905D P231
>> - GXM S912 Q200
>> - GXM S912 Q201
>>
>> To get the HCI interface up one has to install bluez-utils and run:
>> hciattach -s115200 /dev/ttyAML1 bcm43xx 2000000 flow -
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> ---
>> arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 +++++++++++-
>> 1 file changed, 11 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
>> index 7a078bef04cd..7db779048091 100644
>> --- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
>> +++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
>> @@ -48,6 +48,7 @@
>> / {
>> aliases {
>> serial0 = &uart_AO;
>> + serial1 = &uart_A;
>> };
>>
>> chosen {
>> @@ -94,12 +95,21 @@
>>
>> sdio_pwrseq: sdio-pwrseq {
>> compatible = "mmc-pwrseq-simple";
>> - reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
>> + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>,
>> + <&gpio GPIOX_17 GPIO_ACTIVE_LOW>;
>> clocks = <&wifi32k>;
>> clock-names = "ext_clock";
>> };
>> };
>>
>> +/* This is connected to the Bluetooth module of the wifi/BT combo chip: */
>> +&uart_A {
>> + status = "okay";
>> + pinctrl-0 = <&uart_a_pins &uart_a_cts_rts_pins>;
>
> Nit: <&uart_a_pins>, <&uart_a_cts_rts_pins> please, like you've done for
> reset-gpios above.
indeed, not sure why I mixed it up. should I also send an update for
the pinctrl-documentation (as it seems to use the same pattern): [0]?
> Regards,
> Andreas
>
>> + pinctrl-names = "default";
>> + uart-has-rtscts;
>> +};
>> +
>> /* This UART is brought out to the DB9 connector */
>> &uart_AO {
>> status = "okay";
>>
>
>
> --
> SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
> GF: Felix Imend?rffer, Jane Smithard, Graham Norton
> HRB 21284 (AG N?rnberg)
[0] http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt?v=4.9#L74
^ permalink raw reply
* [PATCH v2 0/2] phy: Replace the deprecated extcon API
From: Kishon Vijay Abraham I @ 2017-01-16 9:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <587C8DE8.5050106@samsung.com>
On Monday 16 January 2017 02:40 PM, Chanwoo Choi wrote:
> Hi Kishon,
>
> On 2017? 01? 10? 17:16, Chanwoo Choi wrote:
>> Hi Kishon,
>>
>> Could you review these patches or pick up them if there is no any comment?
>
> If there are no comments, could you apply these patches?
merged it already. You should see it phy -next before tomorrow.
Thanks
Kishon
>
>>
>> On 2016? 12? 30? 13:11, Chanwoo Choi wrote:
>>> This patches just replace the deprecated extcon API without any change
>>> of extcon operation and use the resource-managed function for
>>> extcon_register_notifier().
>>>
>>> The new extcon API instead of deprecated API.
>>> - extcon_set_cable_state_() -> extcon_set_state_sync();
>>> - extcon_get_cable_state_() -> extcon_get_state();
>>>
>>> Changes from v1:
>>> - Rebase these patches based on v4.10-rc1.
>>> - Drop the usb/power-supply/chipidea patches.
>>>
>>> Chanwoo Choi (2):
>>> phy: rcar-gen3-usb2: Replace the deprecated extcon API
>>> phy: sun4i-usb: Replace the deprecated extcon API
>>>
>>> drivers/phy/phy-rcar-gen3-usb2.c | 8 ++++----
>>> drivers/phy/phy-sun4i-usb.c | 4 ++--
>>> 2 files changed, 6 insertions(+), 6 deletions(-)
>>>
>>
>
>
^ permalink raw reply
* [PATCH 2/5] phy: meson: add USB2 and USB3 PHY support for Meson GXL
From: Kishon Vijay Abraham I @ 2017-01-16 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126145635.24488-3-martin.blumenstingl@googlemail.com>
Hi,
On Saturday 26 November 2016 08:26 PM, Martin Blumenstingl wrote:
> This adds two new USB PHY drivers found on Meson GXL and GXM SoCs.
Please send them as separate drivers.
>
> The registers for the USB2 PHY block handle a maximum of 4 ports (newer
> SoCs may allow more ports, the driver handles this as long as the
> register length is adjusted in the .dts). The PHY block theoretically
> allows powering down each PHY port separately (by putting it into
> "reset" state). Unfortunately this does not work (my board has 2 USB
> ports, connected to port 1 and 2 of the dwc3's internal hub. When
> leaving the third USB PHY disabled then the hub sees that a device is
> plugged in, but it does not work: "usb usb1-port2: connect-debounce
> failed").
> The USB3 PHY will take care of enabling/disabling all available ports,
> because the USB3 PHY also manages the mode of the USB2 PHYs.
>
> The USB3 PHY actually has three purposes:
> - it provides the USB3 PHY
> - it handles the OTG device/host mode detection interrupt
> - it notifies the corresponding USB2 PHYs of the OTG mode changes
> On GXL and GXM SoCs one references all available USB2 PHY ports in the
> USB3 PHY because all are connected to the same USB controller (thus the
> mode will always match). This behavior is configurable via devicetree,
> by passing (or not passing) a list of other ("child") PHYs which should
> be configured by the USB3 PHY.
>
> Unfortunately there are no datasheets available for any of these PHYs.
> Both drivers were written by reading the reference drivers provided by
> Amlogic and analyzing the registers on the kernel that was shipped with
> my board.
>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
> drivers/phy/Kconfig | 13 ++
> drivers/phy/Makefile | 2 +
> drivers/phy/phy-meson-gxl-usb2.c | 374 ++++++++++++++++++++++++++++++++++++++
> drivers/phy/phy-meson-gxl-usb3.c | 377 +++++++++++++++++++++++++++++++++++++++
> 4 files changed, 766 insertions(+)
> create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
> create mode 100644 drivers/phy/phy-meson-gxl-usb3.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 728e03f..ea74843 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -502,4 +502,17 @@ config PHY_MESON8B_USB2
> and GXBB SoCs.
> If unsure, say N.
>
> +config PHY_MESON_GXL_USB
> + tristate "Meson GXL USB2 and USB3 PHY drivers"
> + default ARCH_MESON
> + depends on OF && (ARCH_MESON || COMPILE_TEST)
> + depends on USB_SUPPORT
> + select USB_COMMON
> + select GENERIC_PHY
> + select REGMAP_MMIO
> + help
> + Enable this to support the Meson USB2 and USB3 PHYs found in
> + Meson GXL SoCs.
> + If unsure, say N.
> +
> endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 0c7fdae..960a96e 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -61,3 +61,5 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
> obj-$(CONFIG_ARCH_TEGRA) += tegra/
> obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
> obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb3.o
> diff --git a/drivers/phy/phy-meson-gxl-usb2.c b/drivers/phy/phy-meson-gxl-usb2.c
> new file mode 100644
> index 0000000..c081ce3
> --- /dev/null
> +++ b/drivers/phy/phy-meson-gxl-usb2.c
> @@ -0,0 +1,374 @@
> +/*
> + * Meson GXL USB2 PHY driver
> + *
> + * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/usb/of.h>
> +
> +/* bits [31:27] are read-only */
> +#define U2P_R0 0x0
> + #define U2P_R0_BYPASS_SEL BIT(0)
> + #define U2P_R0_BYPASS_DM_EN BIT(1)
> + #define U2P_R0_BYPASS_DP_EN BIT(2)
> + #define U2P_R0_TXBITSTUFF_ENH BIT(3)
> + #define U2P_R0_TXBITSTUFF_EN BIT(4)
> + #define U2P_R0_DM_PULLDOWN BIT(5)
> + #define U2P_R0_DP_PULLDOWN BIT(6)
> + #define U2P_R0_DP_VBUS_VLD_EXT_SEL BIT(7)
> + #define U2P_R0_DP_VBUS_VLD_EXT BIT(8)
> + #define U2P_R0_ADP_PRB_EN BIT(9)
> + #define U2P_R0_ADP_DISCHARGE BIT(10)
> + #define U2P_R0_ADP_CHARGE BIT(11)
> + #define U2P_R0_DRV_VBUS BIT(12)
> + #define U2P_R0_ID_PULLUP BIT(13)
> + #define U2P_R0_LOOPBACK_EN_B BIT(14)
> + #define U2P_R0_OTG_DISABLE BIT(15)
> + #define U2P_R0_COMMON_ONN BIT(16)
> + #define U2P_R0_FSEL_SHIFT 17
> + #define U2P_R0_FSEL_MASK GENMASK(19, 17)
> + #define U2P_R0_REF_CLK_SEL_SHIFT 20
> + #define U2P_R0_REF_CLK_SEL_MASK GENMASK(21, 20)
> + #define U2P_R0_POWER_ON_RESET BIT(22)
> + #define U2P_R0_V_ATE_TEST_EN_B_SHIFT 23
> + #define U2P_R0_V_ATE_TEST_EN_B_MASK GENMASK(24, 23)
> + #define U2P_R0_ID_SET_ID_DQ BIT(25)
> + #define U2P_R0_ATE_RESET BIT(26)
> + #define U2P_R0_FSV_MINUS BIT(27)
> + #define U2P_R0_FSV_PLUS BIT(28)
> + #define U2P_R0_BYPASS_DM_DATA BIT(29)
> + #define U2P_R0_BYPASS_DP_DATA BIT(30)
> +
> +#define U2P_R1 0x4
> + #define U2P_R1_BURN_IN_TEST BIT(0)
> + #define U2P_R1_ACA_ENABLE BIT(1)
> + #define U2P_R1_DCD_ENABLE BIT(2)
> + #define U2P_R1_VDAT_SRC_EN_B BIT(3)
> + #define U2P_R1_VDAT_DET_EN_B BIT(4)
> + #define U2P_R1_CHARGES_SEL BIT(5)
> + #define U2P_R1_TX_PREEMP_PULSE_TUNE BIT(6)
> + #define U2P_R1_TX_PREEMP_AMP_TUNE_SHIFT 7
> + #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK GENMASK(8, 7)
> + #define U2P_R1_TX_RES_TUNE_SHIFT 9
> + #define U2P_R1_TX_RES_TUNE_MASK GENMASK(10, 9)
> + #define U2P_R1_TX_RISE_TUNE_SHIFT 11
> + #define U2P_R1_TX_RISE_TUNE_MASK GENMASK(12, 11)
> + #define U2P_R1_TX_VREF_TUNE_SHIFT 13
> + #define U2P_R1_TX_VREF_TUNE_MASK GENMASK(16, 13)
> + #define U2P_R1_TX_FSLS_TUNE_SHIFT 17
> + #define U2P_R1_TX_FSLS_TUNE_MASK GENMASK(20, 17)
> + #define U2P_R1_TX_HSXV_TUNE_SHIFT 21
> + #define U2P_R1_TX_HSXV_TUNE_MASK GENMASK(22, 21)
> + #define U2P_R1_OTG_TUNE_SHIFT 23
> + #define U2P_R1_OTG_TUNE_MASK GENMASK(25, 23)
> + #define U2P_R1_SQRX_TUNE_SHIFT 26
> + #define U2P_R1_SQRX_TUNE_MASK GENMASK(28, 26)
> + #define U2P_R1_COMP_DIS_TUNE_SHIFT 29
> + #define U2P_R1_COMP_DIS_TUNE_MASK GENMASK(31, 29)
> +
> +/* bits [31:14] are read-only */
> +#define U2P_R2 0x8
> + #define U2P_R2_DATA_IN_SHIFT 0
> + #define U2P_R2_DATA_IN_MASK GENMASK(3, 0)
> + #define U2P_R2_DATA_IN_EN_SHIFT 4
> + #define U2P_R2_DATA_IN_EN_MASK GENMASK(7, 4)
> + #define U2P_R2_ADDR_SHIFT 8
> + #define U2P_R2_ADDR_MASK GENMASK(11, 8)
> + #define U2P_R2_DATA_OUT_SEL BIT(12)
> + #define U2P_R2_CLK BIT(13)
> + #define U2P_R2_DATA_OUT_SHIFT 14
> + #define U2P_R2_DATA_OUT_MASK GENMASK(17, 14)
> + #define U2P_R2_ACA_PIN_RANGE_C BIT(18)
> + #define U2P_R2_ACA_PIN_RANGE_B BIT(19)
> + #define U2P_R2_ACA_PIN_RANGE_A BIT(20)
> + #define U2P_R2_ACA_PIN_GND BIT(21)
> + #define U2P_R2_ACA_PIN_FLOAT BIT(22)
> + #define U2P_R2_CHARGE_DETECT BIT(23)
> + #define U2P_R2_DEVICE_SESSION_VALID BIT(24)
> + #define U2P_R2_ADP_PROBE BIT(25)
> + #define U2P_R2_ADP_SENSE BIT(26)
> + #define U2P_R2_SESSION_END BIT(27)
> + #define U2P_R2_VBUS_VALID BIT(28)
> + #define U2P_R2_B_VALID BIT(29)
> + #define U2P_R2_A_VALID BIT(30)
> + #define U2P_R2_ID_DIG BIT(31)
> +
> +#define U2P_R3 0xc
> +
> +#define PHY_PORT_RESOURCE_SIZE 0x20
> +
> +#define RESET_COMPLETE_TIME 500
> +
> +struct phy_meson_gxl_usb2_priv {
> + struct regmap *regmap;
> + enum phy_mode mode;
> +};
> +
> +struct phy_meson_gxl_usb2_drv {
> + void __iomem *base;
> + int num_ports;
> + struct phy **ports;
> + struct clk *clk_usb;
> + struct clk *clk_usb_ddr;
> +};
> +
> +static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = U2P_R3,
> +};
> +
> +static int phy_meson_gxl_usb2_set_mode(struct phy *phy, enum phy_mode mode)
> +{
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> + switch (mode) {
> + case PHY_MODE_USB_HOST:
> + case PHY_MODE_USB_OTG:
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> + U2P_R0_DM_PULLDOWN);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> + U2P_R0_DP_PULLDOWN);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP, 0);
> + break;
> +
> + case PHY_MODE_USB_DEVICE:
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> + 0);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> + 0);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP,
> + U2P_R0_ID_PULLUP);
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + /* reset the PHY and wait until settings are stabilized */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> + U2P_R0_POWER_ON_RESET);
> + udelay(RESET_COMPLETE_TIME);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
> + udelay(RESET_COMPLETE_TIME);
> +
> + priv->mode = mode;
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_off(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb2_drv *drv_priv =
> + dev_get_drvdata(phy->dev.parent);
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> + /* power off the PHY by putting it into reset mode */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> + U2P_R0_POWER_ON_RESET);
> +
> + clk_disable_unprepare(drv_priv->clk_usb_ddr);
> + clk_disable_unprepare(drv_priv->clk_usb);
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_on(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb2_drv *drv_priv =
> + dev_get_drvdata(phy->dev.parent);
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> + int ret;
> +
> + ret = clk_prepare_enable(drv_priv->clk_usb);
> + if (ret) {
> + dev_err(&phy->dev, "Failed to enable USB clock\n");
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(drv_priv->clk_usb_ddr);
> + if (ret) {
> + clk_disable_unprepare(drv_priv->clk_usb);
> +
> + dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
> + return ret;
> + }
> +
> + /* power on the PHY by taking it out of reset mode */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
> +
> + ret = phy_meson_gxl_usb2_set_mode(phy, priv->mode);
> + if (ret) {
> + phy_meson_gxl_usb2_power_off(phy);
> +
> + dev_err(&phy->dev, "Failed to initialize PHY with mode %d\n",
> + priv->mode);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct phy_ops phy_meson_gxl_usb2_ops = {
> + .power_on = phy_meson_gxl_usb2_power_on,
> + .power_off = phy_meson_gxl_usb2_power_off,
> + .set_mode = phy_meson_gxl_usb2_set_mode,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct phy *phy_meson_gxl_usb2_of_xlate(struct device *dev,
> + struct of_phandle_args *args)
> +{
> + struct phy_meson_gxl_usb2_drv *priv = dev_get_drvdata(dev);
> + int port;
> +
> + if (args->args_count != 1) {
> + dev_err(dev, "Invalid number of cells in 'phy' property\n");
> + return ERR_PTR(-ENODEV);
> + }
> +
> + port = args->args[0];
> + if (WARN_ON(port >= priv->num_ports))
> + return ERR_PTR(-ENODEV);
> +
> + return priv->ports[port];
> +}
Please model every port as a sub-node and get rid of custom xlate implementation.
> +
> +static int phy_meson_gxl_usb2_probe_port(struct device *dev, int port)
> +{
> + struct phy_meson_gxl_usb2_drv *drv_priv = dev_get_drvdata(dev);
> + struct phy_meson_gxl_usb2_priv *phy_priv;
> + struct phy *phy;
> + void __iomem *port_base;
> +
> + phy_priv = devm_kzalloc(dev, sizeof(*phy_priv), GFP_KERNEL);
> + if (!phy_priv)
> + return -ENOMEM;
> +
> + switch (of_usb_get_dr_mode_by_phy(dev->of_node, port)) {
> + case USB_DR_MODE_PERIPHERAL:
> + phy_priv->mode = PHY_MODE_USB_DEVICE;
> + break;
> + case USB_DR_MODE_OTG:
> + phy_priv->mode = PHY_MODE_USB_OTG;
> + break;
> + case USB_DR_MODE_HOST:
> + default:
> + phy_priv->mode = PHY_MODE_USB_HOST;
> + break;
> + }
> +
> + phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
> + if (IS_ERR(phy)) {
> + dev_err(dev, "failed to create PHY port %d\n", port);
> + return PTR_ERR(phy);
> + }
> +
> + port_base = drv_priv->base + (port * PHY_PORT_RESOURCE_SIZE);
> + phy_priv->regmap = devm_regmap_init_mmio(&phy->dev, port_base,
> + &phy_meson_gxl_usb2_regmap_conf);
> + if (IS_ERR(phy_priv->regmap))
> + return PTR_ERR(phy_priv->regmap);
> +
> + phy_set_drvdata(phy, phy_priv);
> +
> + drv_priv->ports[port] = phy;
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct phy_meson_gxl_usb2_drv *priv;
> + struct phy_provider *phy_provider;
> + struct resource *res;
> + int i, ret;
> +
> + ret = device_reset(dev);
> + if (ret) {
> + dev_err(dev, "failed to reset device\n");
> + return ret;
> + }
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, priv);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + priv->base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(priv->base))
> + return PTR_ERR(priv->base);
> +
> + priv->num_ports = resource_size(res) / PHY_PORT_RESOURCE_SIZE;
> + if (priv->num_ports < 1) {
> + dev_err(dev, "specified memory range is too small\n");
> + return -EINVAL;
> + }
> +
> + priv->ports = devm_kcalloc(dev, priv->num_ports, sizeof(*priv->ports),
> + GFP_KERNEL);
> + if (!priv->ports)
> + return -ENOMEM;
> +
> + priv->clk_usb = devm_clk_get(dev, "usb");
> + if (IS_ERR(priv->clk_usb)) {
> + dev_err(dev, "failed to get USB clock\n");
> + return PTR_ERR(priv->clk_usb);
> + }
> +
> + priv->clk_usb_ddr = devm_clk_get(dev, "usb_ddr");
> + if (IS_ERR(priv->clk_usb_ddr)) {
> + dev_err(dev, "failed to get USB DDR clock\n");
> + return PTR_ERR(priv->clk_usb_ddr);
> + }
> +
> + for (i = 0; i < priv->num_ports; i++) {
> + ret = phy_meson_gxl_usb2_probe_port(dev, i);
> + if (ret)
> + return ret;
> + }
> +
> + phy_provider = devm_of_phy_provider_register(dev,
> + phy_meson_gxl_usb2_of_xlate);
> +
> + return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static const struct of_device_id phy_meson_gxl_usb2_of_match[] = {
> + { .compatible = "amlogic,meson-gxl-usb2-phy", },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb2_of_match);
> +
> +static struct platform_driver phy_meson_gxl_usb2_driver = {
> + .probe = phy_meson_gxl_usb2_probe,
> + .driver = {
> + .name = "phy-meson-gxl-usb2",
> + .of_match_table = phy_meson_gxl_usb2_of_match,
> + },
> +};
> +module_platform_driver(phy_meson_gxl_usb2_driver);
> +
> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
> +MODULE_DESCRIPTION("Meson GXL USB2 PHY driver");
> +MODULE_LICENSE("GPL");
GPL v2 to match with the file header.
> diff --git a/drivers/phy/phy-meson-gxl-usb3.c b/drivers/phy/phy-meson-gxl-usb3.c
> new file mode 100644
> index 0000000..90a4028
> --- /dev/null
> +++ b/drivers/phy/phy-meson-gxl-usb3.c
> @@ -0,0 +1,377 @@
> +/*
> + * Meson GXL USB3 PHY driver
> + *
> + * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/usb/of.h>
> +#include <linux/workqueue.h>
> +
> +#define USB_R0 0x00
> + #define USB_R0_P30_FSEL_SHIFT 0
> + #define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
> + #define USB_R0_P30_PHY_RESET BIT(6)
> + #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
> + #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
> + #define USB_R0_P30_ACJT_LEVEL_SHIFT 9
> + #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
> + #define USB_R0_P30_TX_BOOST_LEVEL_SHIFT 14
> + #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
> + #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
> + #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
> + #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_SHIFT 19
> + #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
> + #define USB_R0_U2D_SS_SCALEDOWN_MODE_SHIFT 29
> + #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
> + #define USB_R0_U2D_ACT BIT(31)
> +
> +#define USB_R1 0x04
> + #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
> + #define USB_R1_U3H_PME_ENABLE BIT(1)
> + #define USB_R1_U3H_HUB_PORT_OVERCURRENT_SHIFT 2
> + #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
> + #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_SHIFT 7
> + #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
> + #define USB_R1_U3H_HOST_U2_PORT_DISABLE_SHIFT 12
> + #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
> + #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
> + #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
> + #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
> + #define USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT 19
> + #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
> + #define USB_R1_P30_PCS_TX_SWING_FULL_SHIFT 25
> + #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
> +
> +#define USB_R2 0x08
> + #define USB_R2_P30_CR_DATA_IN_SHIFT 0
> + #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
> + #define USB_R2_P30_CR_READ BIT(16)
> + #define USB_R2_P30_CR_WRITE BIT(17)
> + #define USB_R2_P30_CR_CAP_ADDR BIT(18)
> + #define USB_R2_P30_CR_CAP_DATA BIT(19)
> + #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT 20
> + #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
> + #define USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT 26
> + #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
> +
> +#define USB_R3 0x0c
> + #define USB_R3_P30_SSC_ENABLE BIT(0)
> + #define USB_R3_P30_SSC_RANGE_SHIFT 1
> + #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
> + #define USB_R3_P30_SSC_REF_CLK_SEL_SHIFT 4
> + #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
> + #define USB_R3_P30_REF_SSP_EN BIT(13)
> + #define USB_R3_P30_LOS_BIAS_SHIFT 16
> + #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
> + #define USB_R3_P30_LOS_LEVEL_SHIFT 19
> + #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
> + #define USB_R3_P30_MPLL_MULTIPLIER_SHIFT 24
> + #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
> +
> +#define USB_R4 0x10
> + #define USB_R4_P21_PORT_RESET_0 BIT(0)
> + #define USB_R4_P21_SLEEP_M0 BIT(1)
> + #define USB_R4_MEM_PD_SHIFT 2
> + #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
> + #define USB_R4_P21_ONLY BIT(4)
> +
> +#define USB_R5 0x14
> + #define USB_R5_ID_DIG_SYNC BIT(0)
> + #define USB_R5_ID_DIG_REG BIT(1)
> + #define USB_R5_ID_DIG_CFG_SHIFT 2
> + #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
> + #define USB_R5_ID_DIG_EN_0 BIT(4)
> + #define USB_R5_ID_DIG_EN_1 BIT(5)
> + #define USB_R5_ID_DIG_CURR BIT(6)
> + #define USB_R5_ID_DIG_IRQ BIT(7)
> + #define USB_R5_ID_DIG_TH_SHIFT 8
> + #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
> + #define USB_R5_ID_DIG_CNT_SHIFT 16
> + #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
> +
> +/* read-only register */
> +#define USB_R6 0x18
> + #define USB_R6_P30_CR_DATA_OUT_SHIFT 0
> + #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
> + #define USB_R6_P30_CR_ACK BIT(16)
> +
> +#define RESET_COMPLETE_TIME 500
> +
> +struct phy_meson_gxl_usb3_priv {
> + struct regmap *regmap;
> + struct delayed_work otg_work;
> + struct phy *this_phy;
> + int num_usb2_phys;
> + struct phy **usb2_phys;
> +};
> +
> +static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = USB_R6,
> +};
> +
> +static int phy_meson_gxl_usb3_update_mode(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + u32 val;
> + enum phy_mode mode;
> + int i, ret;
> +
> + ret = regmap_read(priv->regmap, USB_R5, &val);
> + if (ret)
> + return ret;
> +
> + if (val & USB_R5_ID_DIG_CURR) {
> + mode = PHY_MODE_USB_DEVICE;
> +
> + regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
> + USB_R0_U2D_ACT);
> + regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
> + USB_R4_P21_SLEEP_M0);
> + } else {
> + mode = PHY_MODE_USB_HOST;
> +
> + regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
> + regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
> + 0);
> + }
> +
> + /* inform the USB2 PHY that we have changed the mode */
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_set_mode(priv->usb2_phys[i], mode);
I'm finding it difficult to understand this. Why should the mode of one phy be
set from another phy? Maybe this part should be implemented using extcon?
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to update usb2-phy #%d mode to %d\n",
> + i, mode);
> + return ret;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static void phy_meson_gxl_usb3_work(struct work_struct *data)
> +{
> + struct phy_meson_gxl_usb3_priv *priv =
> + container_of(data, struct phy_meson_gxl_usb3_priv,
> + otg_work.work);
> +
> + phy_meson_gxl_usb3_update_mode(priv->this_phy);
> +
> + /* unmask IRQs which may have arrived in the meantime */
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
> +}
> +
> +static int phy_meson_gxl_usb3_init(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_init(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to initialize related usb2-phy #%d\n",
> + i);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb3_exit(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_exit(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to exit related usb2-phy #%d\n", i);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb3_power_on(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_power_on(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to power on related usb2-phy #%d\n",
> + i);
> + return ret;
> + }
> + }
> +
> + regmap_update_bits(priv->regmap, USB_R1,
> + USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
> + 0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT);
> +
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
> + USB_R5_ID_DIG_EN_0);
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
> + USB_R5_ID_DIG_EN_1);
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
> + 0xff << USB_R5_ID_DIG_TH_SHIFT);
> +
> + return phy_meson_gxl_usb3_update_mode(phy);
> +}
> +
> +static int phy_meson_gxl_usb3_power_off(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_power_off(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to power off related usb2-phy #%d\n",
> + i);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static irqreturn_t phy_meson_gxl_usb3_irq(int irq, void *data)
> +{
> + u32 val;
> + struct phy_meson_gxl_usb3_priv *priv = data;
> +
> + regmap_read(priv->regmap, USB_R5, &val);
> + if (!(val & USB_R5_ID_DIG_IRQ)) {
> + dev_err(&priv->this_phy->dev, "spurious interrupt\n");
> + return IRQ_NONE;
> + }
> +
> + schedule_delayed_work(&priv->otg_work, msecs_to_jiffies(10));
> +
> + /* acknowledge the IRQ */
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static const struct phy_ops phy_meson_gxl_usb3_ops = {
> + .init = phy_meson_gxl_usb3_init,
> + .exit = phy_meson_gxl_usb3_exit,
> + .power_on = phy_meson_gxl_usb3_power_on,
> + .power_off = phy_meson_gxl_usb3_power_off,
> + .owner = THIS_MODULE,
> +};
> +
> +static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct phy_meson_gxl_usb3_priv *priv;
> + struct resource *res;
> + struct phy *phy;
> + struct phy_provider *phy_provider;
> + void __iomem *base;
> + int i, irq;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + priv->regmap = devm_regmap_init_mmio(dev, base,
> + &phy_meson_gxl_usb3_regmap_conf);
> + if (IS_ERR(priv->regmap))
> + return PTR_ERR(priv->regmap);
> +
> + irq = platform_get_irq(pdev, 0);
> + if (irq >= 0) {
> + INIT_DELAYED_WORK(&priv->otg_work, phy_meson_gxl_usb3_work);
> +
> + irq = devm_request_irq(dev, irq, phy_meson_gxl_usb3_irq,
> + IRQF_SHARED, dev_name(dev),
> + priv);
> + if (irq < 0) {
> + dev_err(dev, "could not register IRQ handler (%d)\n",
> + irq);
> + return -EINVAL;
> + }
> + }
> +
> + priv->num_usb2_phys = of_count_phandle_with_args(np, "phys",
> + "#phy-cells");
> +
> + priv->usb2_phys = devm_kcalloc(dev, priv->num_usb2_phys,
> + sizeof(*priv->usb2_phys), GFP_KERNEL);
> + if (!priv->usb2_phys)
> + return -ENOMEM;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + priv->usb2_phys[i] = devm_of_phy_get_by_index(dev, np, i);
I'm not sure if referencing usb2_phy from here is the right approach.
Thanks
Kishon
^ permalink raw reply
* [PATCH 2/2] spi: pca2xx-pci: Allow MSI
From: Andy Shevchenko @ 2017-01-16 9:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4061bba80ecc632b219b56d8a8cd25d62658d48a.1484557560.git.jan.kiszka@siemens.com>
On Mon, 2017-01-16 at 10:06 +0100, Jan Kiszka wrote:
> Now that the core is ready for edge-triggered interrupts, we can
> safely
> allow the PCI versions that provide this to enable the feature and,
> thus, have less shared interrupts.
>
My comments below.
> - ?if (IS_ERR(ssp->clk))
> + if (IS_ERR(ssp->clk))
> ? return PTR_ERR(ssp->clk);
This doesn't belong to the patch.
?
> + pci_set_master(dev);
> +
> + ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES);
> + if (ret < 0) {
> + clk_unregister(ssp->clk);
> + return ret;
> + }
> + ssp->irq = pci_irq_vector(dev, 0);
> +
This looks good, though I would put it closer to the initial place of
ssp->irq assignment, i.e. before clock registering.
> + pci_free_irq_vectors(dev);
> + pci_free_irq_vectors(dev);
You know my answer, right? So, please be sure that we are using
pcim_alloc_irq_vectors().
Yes, I know there is (was?) no such API, needs to be created. Currently
this might make a mess on ->remove().
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* [PATCH 1/2] spi: pxa2xx: Prepare for edge-triggered interrupts
From: Andy Shevchenko @ 2017-01-16 9:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6fe26505e67790b27eed28fd7451b51e70b7e8ba.1484557560.git.jan.kiszka@siemens.com>
On Mon, 2017-01-16 at 10:05 +0100, Jan Kiszka wrote:
> When using the a device with edge-triggered interrupts, such as MSIs,
> the interrupt handler has to ensure that there is a point in time
> during
> its execution where all interrupts sources are silent so that a new
> event can trigger a new interrupt again.
>
> This is achieved here by looping over SSSR evaluation. We need to take
> into account that SSCR1 may be changed by the transfer handler, thus
> we
> need to redo the mask calculation, at least regarding the volatile
> interrupt enable bit (TIE).
Could you split this to two patches, one just move the code under
question to a helper function (no functional change), the other does
what you state in commit message here?
>
> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
> ---
> ?drivers/spi/spi-pxa2xx.c | 50 +++++++++++++++++++++++++++----------
> -----------
> ?1 file changed, 28 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
> index dd7b5b4..24bf549 100644
> --- a/drivers/spi/spi-pxa2xx.c
> +++ b/drivers/spi/spi-pxa2xx.c
> @@ -737,6 +737,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
> ? struct driver_data *drv_data = dev_id;
> ? u32 sccr1_reg;
> ? u32 mask = drv_data->mask_sr;
> + irqreturn_t ret = IRQ_NONE;
> ? u32 status;
> ?
> ? /*
> @@ -760,37 +761,42 @@ static irqreturn_t ssp_int(int irq, void
> *dev_id)
> ?
> ? sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
> ?
> - /* Ignore possible writes if we don't need to write */
> - if (!(sccr1_reg & SSCR1_TIE))
> - mask &= ~SSSR_TFS;
> -
> ? /* Ignore RX timeout interrupt if it is disabled */
> ? if (!(sccr1_reg & SSCR1_TINTE))
> ? mask &= ~SSSR_TINT;
> ?
> - if (!(status & mask))
> - return IRQ_NONE;
> + while (1) {
> + /* Ignore possible writes if we don't need to write
> */
> + if (!(sccr1_reg & SSCR1_TIE))
> + mask &= ~SSSR_TFS;
> ?
> - if (!drv_data->master->cur_msg) {
> + if (!(status & mask))
> + return ret;
> ?
> - pxa2xx_spi_write(drv_data, SSCR0,
> - ?pxa2xx_spi_read(drv_data, SSCR0)
> - ?& ~SSCR0_SSE);
> - pxa2xx_spi_write(drv_data, SSCR1,
> - ?pxa2xx_spi_read(drv_data, SSCR1)
> - ?& ~drv_data->int_cr1);
> - if (!pxa25x_ssp_comp(drv_data))
> - pxa2xx_spi_write(drv_data, SSTO, 0);
> - write_SSSR_CS(drv_data, drv_data->clear_sr);
> + if (!drv_data->master->cur_msg) {
> ?
> - dev_err(&drv_data->pdev->dev,
> - "bad message state in interrupt handler\n");
> + pxa2xx_spi_write(drv_data, SSCR0,
> + ?pxa2xx_spi_read(drv_data,
> SSCR0)
> + ?& ~SSCR0_SSE);
> + pxa2xx_spi_write(drv_data, SSCR1,
> + ?pxa2xx_spi_read(drv_data,
> SSCR1)
> + ?& ~drv_data->int_cr1);
> + if (!pxa25x_ssp_comp(drv_data))
> + pxa2xx_spi_write(drv_data, SSTO, 0);
> + write_SSSR_CS(drv_data, drv_data->clear_sr);
> ?
> - /* Never fail */
> - return IRQ_HANDLED;
> - }
> + dev_err(&drv_data->pdev->dev,
> + "bad message state in interrupt
> handler\n");
> ?
> - return drv_data->transfer_handler(drv_data);
> + /* Never fail */
> + return IRQ_HANDLED;
> + }
> +
> + ret |= drv_data->transfer_handler(drv_data);
> +
> + status = pxa2xx_spi_read(drv_data, SSSR);
> + sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
> + }
> ?}
> ?
> ?/*
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* [PATCH 2/3] Broadcom USB DRD Phy driver for Northstar2
From: Kishon Vijay Abraham I @ 2017-01-16 9:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480485338-23451-3-git-send-email-raviteja.garimella@broadcom.com>
Hi,
On Wednesday 30 November 2016 11:25 AM, Raviteja Garimella wrote:
> This is driver for USB DRD Phy used in Broadcom's Northstar2
> SoC. The phy can be configured to be in Device mode or Host
> mode based on the type of cable connected to the port. The
> driver registers to extcon framework to get appropriate
> connect events for Host/Device cables connect/disconnect
> states based on VBUS and ID interrupts.
>
> Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
> ---
> drivers/phy/Kconfig | 13 +
> drivers/phy/Makefile | 1 +
> drivers/phy/phy-bcm-ns2-usbdrd.c | 587 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 601 insertions(+)
> create mode 100644 drivers/phy/phy-bcm-ns2-usbdrd.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index fe00f91..b3b6a73 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -479,6 +479,19 @@ config PHY_CYGNUS_PCIE
> Enable this to support the Broadcom Cygnus PCIe PHY.
> If unsure, say N.
>
> +config PHY_NS2_USB_DRD
> + tristate "Broadcom Northstar2 USB DRD PHY support"
> + depends on OF && (ARCH_BCM_IPROC || COMPILE_TEST)
> + select GENERIC_PHY
> + select EXTCON
> + default ARCH_BCM_IPROC
> + help
> + Enable this to support the Broadcom Northstar2 USB DRD PHY.
> + This driver initializes the PHY in either HOST or DEVICE mode.
> + The host or device configuration is read from device tree.
> +
> + If unsure, say N.
> +
> source "drivers/phy/tegra/Kconfig"
>
> config PHY_NS2_PCIE
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index a534cf5..b733ba2 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -58,5 +58,6 @@ obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
> obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
> obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
> obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
> +obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bcm-ns2-usbdrd.o
> obj-$(CONFIG_ARCH_TEGRA) += tegra/
> obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
> diff --git a/drivers/phy/phy-bcm-ns2-usbdrd.c b/drivers/phy/phy-bcm-ns2-usbdrd.c
> new file mode 100644
> index 0000000..460040d
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-ns2-usbdrd.c
> @@ -0,0 +1,587 @@
> +/*
> + * Copyright (C) 2016 Broadcom
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/extcon.h>
> +#include <linux/gpio.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +
> +#define ICFG_DRD_AFE 0x0
> +#define ICFG_MISC_STAT 0x18
> +#define ICFG_DRD_P0CTL 0x1C
> +#define ICFG_STRAP_CTRL 0x20
> +#define ICFG_FSM_CTRL 0x24
> +
> +#define IDM_RST_BIT BIT(0)
> +#define AFE_CORERDY_VDDC BIT(18)
> +#define PHY_PLL_RESETB BIT(15)
> +#define PHY_RESETB BIT(14)
> +#define PHY_PLL_LOCK BIT(0)
> +
> +#define DRD_DEV_MODE BIT(20)
> +#define OHCI_OVRCUR_POL BIT(11)
> +#define ICFG_OFF_MODE BIT(6)
> +#define PLL_LOCK_RETRY 1000
> +
> +#define EVT_DEVICE 0
> +#define EVT_HOST 1
> +#define EVT_IDLE 2
> +
> +#define DRD_HOST_MODE (BIT(2) | BIT(3))
> +#define DRD_DEVICE_MODE (BIT(4) | BIT(5))
> +#define DRD_HOST_VAL 0x803
> +#define DRD_DEV_VAL 0x807
> +#define GPIO_DELAY 20
> +#define PHY_WQ_DELAY msecs_to_jiffies(600)
> +
> +struct ns2_phy_data;
> +struct ns2_phy_driver {
> + void __iomem *icfgdrd_regs;
> + void __iomem *idmdrd_rst_ctrl;
> + void __iomem *crmu_usb2_ctrl;
> + void __iomem *usb2h_strap_reg;
> + spinlock_t lock; /* spin lock for phy driver */
> + bool host_mode;
> + struct ns2_phy_data *data;
> + struct extcon_specific_cable_nb extcon_dev;
> + struct extcon_specific_cable_nb extcon_host;
> + struct notifier_block host_nb;
> + struct notifier_block dev_nb;
> + struct delayed_work conn_work;
> + struct extcon_dev *edev;
> + struct gpio_desc *vbus_gpiod;
> + struct gpio_desc *id_gpiod;
> + int id_irq;
> + int vbus_irq;
> + unsigned long debounce_jiffies;
> + struct delayed_work wq_extcon;
> +};
> +
> +struct ns2_phy_data {
> + struct ns2_phy_driver *driver;
> + struct phy *phy;
> + int new_state;
> + bool poweron;
> +};
> +
> +static const unsigned int usb_extcon_cable[] = {
> + EXTCON_USB,
> + EXTCON_USB_HOST,
> + EXTCON_NONE,
> +};
> +
> +static inline int pll_lock_stat(u32 usb_reg, int reg_mask,
> + struct ns2_phy_driver *driver)
> +{
> + int retry = PLL_LOCK_RETRY;
> + u32 val;
> +
> + do {
> + udelay(1);
> + val = readl(driver->icfgdrd_regs + usb_reg);
> + if (val & reg_mask)
> + return 0;
> + } while (--retry > 0);
> +
> + return -EBUSY;
> +}
> +
> +static int ns2_drd_phy_init(struct phy *phy)
> +{
> + struct ns2_phy_data *data = phy_get_drvdata(phy);
> + struct ns2_phy_driver *driver = data->driver;
> + unsigned long flags;
> + u32 val;
> +
> + spin_lock_irqsave(&driver->lock, flags);
> +
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + if (data->new_state == EVT_HOST) {
> + val &= ~DRD_DEVICE_MODE;
> + val |= DRD_HOST_MODE;
> + } else {
> + val &= ~DRD_HOST_MODE;
> + val |= DRD_DEVICE_MODE;
> + }
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + spin_unlock_irqrestore(&driver->lock, flags);
> + return 0;
> +}
> +
> +static int ns2_drd_phy_shutdown(struct phy *phy)
> +{
> + struct ns2_phy_data *data = phy_get_drvdata(phy);
> + struct ns2_phy_driver *driver = data->driver;
> + unsigned long flags;
> + u32 val;
> +
> + spin_lock_irqsave(&driver->lock, flags);
> + if (!data->poweron)
> + goto exit;
> +
> + val = readl(driver->crmu_usb2_ctrl);
> + val &= ~AFE_CORERDY_VDDC;
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + driver->host_mode = 0;
> + val = readl(driver->crmu_usb2_ctrl);
> + val &= ~DRD_DEV_MODE;
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + /* Disable Host and Device Mode */
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> + val &= ~(DRD_HOST_MODE | DRD_DEVICE_MODE | ICFG_OFF_MODE);
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + data->poweron = 0;
> +exit:
> + spin_unlock_irqrestore(&driver->lock, flags);
> + return 0;
> +}
> +
> +static int ns2_drd_phy_poweron(struct phy *phy)
> +{
> + struct ns2_phy_data *data = phy_get_drvdata(phy);
> + struct ns2_phy_driver *driver = data->driver;
> + u32 extcon_event = data->new_state;
> + unsigned long flags;
> + int ret;
> + u32 val;
> +
> + spin_lock_irqsave(&driver->lock, flags);
> + if (extcon_event == EVT_DEVICE) {
> + if (data->poweron)
> + goto exit;
> +
> + writel(DRD_DEV_VAL, driver->icfgdrd_regs + ICFG_DRD_P0CTL);
> +
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> + val &= ~(DRD_HOST_MODE | ICFG_OFF_MODE);
> + val |= DRD_DEVICE_MODE;
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + val = readl(driver->idmdrd_rst_ctrl);
> + val &= ~IDM_RST_BIT;
> + writel(val, driver->idmdrd_rst_ctrl);
> +
> + val = readl(driver->crmu_usb2_ctrl);
> + val |= (AFE_CORERDY_VDDC | DRD_DEV_MODE);
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + /* Bring PHY and PHY_PLL out of Reset */
> + val = readl(driver->crmu_usb2_ctrl);
> + val |= (PHY_PLL_RESETB | PHY_RESETB);
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + ret = pll_lock_stat(ICFG_MISC_STAT, PHY_PLL_LOCK, driver);
> + if (ret < 0) {
> + dev_err(&phy->dev, "Phy PLL lock failed\n");
> + goto err_shutdown;
> + }
> + } else {
> + if (data->poweron && driver->host_mode)
> + goto exit;
> +
> + writel(DRD_HOST_VAL, driver->icfgdrd_regs + ICFG_DRD_P0CTL);
> +
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> + val &= ~(DRD_DEVICE_MODE | ICFG_OFF_MODE);
> + val |= DRD_HOST_MODE;
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + val = readl(driver->crmu_usb2_ctrl);
> + val |= AFE_CORERDY_VDDC;
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + ret = pll_lock_stat(ICFG_MISC_STAT, PHY_PLL_LOCK, driver);
> + if (ret < 0) {
> + dev_err(&phy->dev, "Phy PLL lock failed\n");
> + goto err_shutdown;
> + }
> +
> + val = readl(driver->idmdrd_rst_ctrl);
> + val &= ~IDM_RST_BIT;
> + writel(val, driver->idmdrd_rst_ctrl);
> +
> + /* port over current Polarity */
> + val = readl(driver->usb2h_strap_reg);
> + val |= OHCI_OVRCUR_POL;
> + writel(val, driver->usb2h_strap_reg);
> +
> + driver->host_mode = 1;
> + }
> +
> + data->poweron = 1;
> +exit:
> + spin_unlock_irqrestore(&driver->lock, flags);
> + return 0;
> +
> +err_shutdown:
> + data->poweron = 1;
> + spin_unlock_irqrestore(&driver->lock, flags);
> + ns2_drd_phy_shutdown(phy);
> + return ret;
> +}
> +
> +static void connect_work(struct work_struct *work)
> +{
> + struct ns2_phy_driver *driver;
> + struct ns2_phy_data *data;
> + u32 extcon_event;
> +
> + driver = container_of(to_delayed_work(work),
> + struct ns2_phy_driver, conn_work);
> + data = driver->data;
> + extcon_event = data->new_state;
> +
> + if (extcon_event == EVT_DEVICE || extcon_event == EVT_HOST) {
> + ns2_drd_phy_init(data->phy);
> + ns2_drd_phy_poweron(data->phy);
> + } else if (extcon_event == EVT_IDLE) {
> + ns2_drd_phy_shutdown(data->phy);
> + }
> +}
> +
> +static int drd_device_notify(struct notifier_block *self,
> + unsigned long event, void *ptr)
> +{
> + struct ns2_phy_driver *driver = container_of(self,
> + struct ns2_phy_driver, dev_nb);
> +
> + if (event) {
> + pr_debug("Device connected\n");
> + driver->data->new_state = EVT_DEVICE;
> + schedule_delayed_work(&driver->conn_work, 0);
> + } else {
> + pr_debug("Device disconnected\n");
> + driver->data->new_state = EVT_IDLE;
> + schedule_delayed_work(&driver->conn_work, PHY_WQ_DELAY);
> + }
> +
> + return NOTIFY_DONE;
> +}
> +
> +static int drd_host_notify(struct notifier_block *self,
> + unsigned long event, void *ptr)
> +{
> + struct ns2_phy_driver *driver = container_of(self,
> + struct ns2_phy_driver, host_nb);
> +
> + if (event) {
> + pr_debug("Host connected\n");
> + driver->data->new_state = EVT_HOST;
> + schedule_delayed_work(&driver->conn_work, 0);
> + } else {
> + pr_debug("Host disconnected\n");
> + driver->data->new_state = EVT_IDLE;
> + schedule_delayed_work(&driver->conn_work, PHY_WQ_DELAY);
> + }
> +
> + return NOTIFY_DONE;
> +}
> +
> +static void extcon_work(struct work_struct *work)
> +{
> + struct ns2_phy_driver *driver;
> + int vbus;
> + int id;
> +
> + driver = container_of(to_delayed_work(work),
> + struct ns2_phy_driver, wq_extcon);
> +
> + id = gpiod_get_value_cansleep(driver->id_gpiod);
> + vbus = gpiod_get_value_cansleep(driver->vbus_gpiod);
> +
> + if (!id && vbus) {
> + extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, true);
> + } else if (id && !vbus) {
> + extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, false);
> + extcon_set_cable_state_(driver->edev, EXTCON_USB, false);
> + } else if (id && vbus) {
> + extcon_set_cable_state_(driver->edev, EXTCON_USB, true);
> + }
> +}
> +
> +static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
> +{
> + struct ns2_phy_driver *driver = dev_id;
> +
> + queue_delayed_work(system_power_efficient_wq, &driver->wq_extcon,
> + driver->debounce_jiffies);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int register_extcon_notifier(struct ns2_phy_driver *phy_driver,
> + struct device *dev)
> +{
> + struct extcon_dev *edev;
> + int ret;
> +
> + phy_driver->host_nb.notifier_call = drd_host_notify;
> + phy_driver->dev_nb.notifier_call = drd_device_notify;
> +
> + edev = phy_driver->edev;
> +
> + /* Register for device change notification */
> + ret = extcon_register_notifier(edev, EXTCON_USB,
> + &phy_driver->dev_nb);
> + if (ret < 0) {
> + dev_err(dev, "can't register extcon_dev for %s\n", edev->name);
> + return ret;
> + }
> +
> + /* Register for host change notification */
> + ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
> + &phy_driver->host_nb);
> + if (ret < 0) {
> + dev_err(dev, "can't register extcon_dev for %s\n", edev->name);
> + goto err_dev;
> + }
> +
> + /* Check the device cable connect state */
> + ret = extcon_get_cable_state_(edev, EXTCON_USB);
> + if (ret < 0) {
> + dev_err(dev, "can't get extcon_dev state for %s\n", edev->name);
> + goto err_host;
> + } else if (ret) {
> + phy_driver->data->new_state = EVT_DEVICE;
> + }
> +
> + /* Check the host cable connect state */
> + ret = extcon_get_cable_state_(edev, EXTCON_USB_HOST);
> + if (ret < 0) {
> + dev_err(dev, "can't get extcon_dev state for %s\n", edev->name);
> + goto err_host;
> + } else if (ret) {
> + phy_driver->data->new_state = EVT_HOST;
> + }
> +
> + return 0;
> +
> +err_host:
> + ret = extcon_unregister_notifier(edev, EXTCON_USB_HOST,
> + &phy_driver->host_nb);
> +err_dev:
> + ret = extcon_unregister_notifier(edev, EXTCON_USB,
> + &phy_driver->dev_nb);
> + return ret;
> +}
> +
> +static struct phy_ops ops = {
> + .init = ns2_drd_phy_init,
Is this really being used by any controller driver? Can you point me to the
controller driver that is using this driver?
> + .power_on = ns2_drd_phy_poweron,
> + .power_off = ns2_drd_phy_shutdown,
missing .owner.
Thanks
Kishon
^ permalink raw reply
* [PATCH 0/6] USB support for Broadcom NSP SoC
From: Kishon Vijay Abraham I @ 2017-01-16 9:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <79483fc3-5e91-a1f0-1dbf-1987682373e6@gmail.com>
On Tuesday 13 December 2016 07:50 AM, Florian Fainelli wrote:
> On 11/09/2016 01:33 AM, Yendapally Reddy Dhananjaya Reddy wrote:
>> This patch set contains the usb support for Broadcom NSP SoC.
>> The usb phy is connected through mdio interface. The mdio interface
>> can be used to access either internal phys or external phys using a
>> multiplexer.
>>
>> The first patch provides the documentation details for mdio-mux and
>> second patch provides the documentation details for usb3 phy. The third
>> patch contains the mdio-mux support and fourth patch contains the
>> changes to the mdio bus driver.
>>
>> The fifth patch provides the phy driver and sixth patch provides the
>> enable method for usb.
>>
>> This patch series has been tested on NSP bcm958625HR board.
>> This patch series is based on v4.9.0-rc1 and is available from github-
>> repo: https://github.com/Broadcom/cygnus-linux.git
>> branch:nsp-usb-v1
>
> Can you resubmit this patch series with the feedback from Andrew, Rob
> and Scott addressed?
can the phy patches be re-submitted based on latest mainline and addressing
those feedbacks?
Thanks
Kishon
^ permalink raw reply
* [PATCH] drivers: phy: constify phy_ops structures
From: Kishon Vijay Abraham I @ 2017-01-16 9:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483871756-19008-1-git-send-email-bhumirks@gmail.com>
On Sunday 08 January 2017 04:05 PM, Bhumika Goyal wrote:
> Declare phy_ops structures as const as they are only passed as an
> argument to the function devm_phy_create. This argument is of type const
> struct phy_ops *, so phy_ops structures having this property can be
> declared as const.
> Done using Coccinelle:
removed the rest of commit message and merged.
Thanks
Kishon
>
> @r1 disable optional_qualifier @
> identifier i;
> position p;
> @@
> static struct phy_ops i at p = {...};
>
> @ok1@
> identifier r1.i;
> position p;
> @@
> devm_phy_create(...,&i at p)
>
> @bad@
> position p!={r1.p,ok1.p};
> identifier r1.i;
> @@
> i at p
>
> @depends on !bad disable optional_qualifier@
> identifier r1.i;
> @@
> +const
> struct phy_ops i;
>
> File size details:
>
> text data bss dec hex filename
> 1504 264 0 1768 6e8 phy/phy-bcm-cygnus-pcie.o
> 1576 192 0 1768 6e8 phy/phy-bcm-cygnus-pcie.o
>
> 1083 264 0 1347 543 phy/phy-hi6220-usb.o
> 1155 192 0 1347 543 phy/phy-hi6220-usb.o
>
> 2767 264 0 3031 bd7 phy/phy-mt65xx-usb3.o
> 2829 192 0 3021 bcd phy/phy-mt65xx-usb3.o
>
> 2710 304 0 3014 bc6 phy/phy-rcar-gen3-usb2.o
> 2766 240 0 3006 bbe phy/phy-rcar-gen3-usb2.o
>
> Signed-off-by: Bhumika Goyal <bhumirks@gmail.com>
> ---
> drivers/phy/phy-bcm-cygnus-pcie.c | 2 +-
> drivers/phy/phy-hi6220-usb.c | 2 +-
> drivers/phy/phy-mt65xx-usb3.c | 2 +-
> drivers/phy/phy-rcar-gen3-usb2.c | 2 +-
> 4 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/phy/phy-bcm-cygnus-pcie.c b/drivers/phy/phy-bcm-cygnus-pcie.c
> index 082c03f..0f4ac5d 100644
> --- a/drivers/phy/phy-bcm-cygnus-pcie.c
> +++ b/drivers/phy/phy-bcm-cygnus-pcie.c
> @@ -114,7 +114,7 @@ static int cygnus_pcie_phy_power_off(struct phy *p)
> return cygnus_pcie_power_config(phy, false);
> }
>
> -static struct phy_ops cygnus_pcie_phy_ops = {
> +static const struct phy_ops cygnus_pcie_phy_ops = {
> .power_on = cygnus_pcie_phy_power_on,
> .power_off = cygnus_pcie_phy_power_off,
> .owner = THIS_MODULE,
> diff --git a/drivers/phy/phy-hi6220-usb.c b/drivers/phy/phy-hi6220-usb.c
> index b2141cb..398c102 100644
> --- a/drivers/phy/phy-hi6220-usb.c
> +++ b/drivers/phy/phy-hi6220-usb.c
> @@ -112,7 +112,7 @@ static int hi6220_phy_exit(struct phy *phy)
> return hi6220_phy_setup(priv, false);
> }
>
> -static struct phy_ops hi6220_phy_ops = {
> +static const struct phy_ops hi6220_phy_ops = {
> .init = hi6220_phy_start,
> .exit = hi6220_phy_exit,
> .owner = THIS_MODULE,
> diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c
> index 4d85e73..d972067 100644
> --- a/drivers/phy/phy-mt65xx-usb3.c
> +++ b/drivers/phy/phy-mt65xx-usb3.c
> @@ -506,7 +506,7 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
> return instance->phy;
> }
>
> -static struct phy_ops mt65xx_u3phy_ops = {
> +static const struct phy_ops mt65xx_u3phy_ops = {
> .init = mt65xx_phy_init,
> .exit = mt65xx_phy_exit,
> .power_on = mt65xx_phy_power_on,
> diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c
> index c63da1b..17be045 100644
> --- a/drivers/phy/phy-rcar-gen3-usb2.c
> +++ b/drivers/phy/phy-rcar-gen3-usb2.c
> @@ -350,7 +350,7 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
> return ret;
> }
>
> -static struct phy_ops rcar_gen3_phy_usb2_ops = {
> +static const struct phy_ops rcar_gen3_phy_usb2_ops = {
> .init = rcar_gen3_phy_usb2_init,
> .exit = rcar_gen3_phy_usb2_exit,
> .power_on = rcar_gen3_phy_usb2_power_on,
>
^ permalink raw reply
* [PATCH v2 0/2] phy: Replace the deprecated extcon API
From: Chanwoo Choi @ 2017-01-16 9:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <58749873.4070302@samsung.com>
Hi Kishon,
On 2017? 01? 10? 17:16, Chanwoo Choi wrote:
> Hi Kishon,
>
> Could you review these patches or pick up them if there is no any comment?
If there are no comments, could you apply these patches?
>
> On 2016? 12? 30? 13:11, Chanwoo Choi wrote:
>> This patches just replace the deprecated extcon API without any change
>> of extcon operation and use the resource-managed function for
>> extcon_register_notifier().
>>
>> The new extcon API instead of deprecated API.
>> - extcon_set_cable_state_() -> extcon_set_state_sync();
>> - extcon_get_cable_state_() -> extcon_get_state();
>>
>> Changes from v1:
>> - Rebase these patches based on v4.10-rc1.
>> - Drop the usb/power-supply/chipidea patches.
>>
>> Chanwoo Choi (2):
>> phy: rcar-gen3-usb2: Replace the deprecated extcon API
>> phy: sun4i-usb: Replace the deprecated extcon API
>>
>> drivers/phy/phy-rcar-gen3-usb2.c | 8 ++++----
>> drivers/phy/phy-sun4i-usb.c | 4 ++--
>> 2 files changed, 6 insertions(+), 6 deletions(-)
>>
>
--
Best Regards,
Chanwoo Choi
S/W Center, Samsung Electronics
^ permalink raw reply
* [PATCH v2 2/2] phy: sun4i-usb: Replace the deprecated extcon API
From: Kishon Vijay Abraham I @ 2017-01-16 9:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483071089-8362-3-git-send-email-cw00.choi@samsung.com>
On Friday 30 December 2016 09:41 AM, Chanwoo Choi wrote:
> This patch replaces the deprecated extcon API as following:
> - extcon_set_cable_state_() -> extcon_set_state_sync()
>
> Cc: Kishon Vijay Abraham I <kishon@ti.com>
> Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
> Cc: Chen-Yu Tsai <wens@csie.org>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
merged both the patches in this series.
Thanks
Kishon
> ---
> drivers/phy/phy-sun4i-usb.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
> index bf28a0fdd569..eae171e18043 100644
> --- a/drivers/phy/phy-sun4i-usb.c
> +++ b/drivers/phy/phy-sun4i-usb.c
> @@ -534,7 +534,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
> mutex_unlock(&phy0->mutex);
>
> if (id_notify) {
> - extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST,
> + extcon_set_state_sync(data->extcon, EXTCON_USB_HOST,
> !id_det);
> /* When leaving host mode force end the session here */
> if (force_session_end && id_det == 1) {
> @@ -547,7 +547,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
> }
>
> if (vbus_notify)
> - extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det);
> + extcon_set_state_sync(data->extcon, EXTCON_USB, vbus_det);
>
> if (sun4i_usb_phy0_poll(data))
> queue_delayed_work(system_wq, &data->detect, POLL_TIME);
>
^ permalink raw reply
* [PATCH v8 00/18] KVM PCIe/MSI passthrough on ARM/ARM64 and IOVA reserved regions
From: Auger Eric @ 2017-01-16 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <e1e6d9cf-5fb8-e118-3a47-4c6be77c21a3@semihalf.com>
Hi Tomasz,
On 13/01/2017 14:59, Tomasz Nowicki wrote:
> Hello Eric,
>
> On 11.01.2017 10:41, Eric Auger wrote:
>> Following LPC discussions, we now report reserved regions through
>> the iommu-group sysfs reserved_regions attribute file.
>>
>> Reserved regions are populated through the IOMMU get_resv_region
>> callback (former get_dm_regions), now implemented by amd-iommu,
>> intel-iommu and arm-smmu:
>> - the intel-iommu reports the [0xfee00000 - 0xfeefffff] MSI window
>> as a reserved region and RMRR regions as direct-mapped regions.
>> - the amd-iommu reports device direct mapped regions, the MSI region
>> and HT regions.
>> - the arm-smmu reports the MSI window (arbitrarily located at
>> 0x8000000 and 1MB large).
>>
>> Unsafe interrupt assignment is tested by enumerating all MSI irq
>> domains and checking MSI remapping is supported in the above hierarchy.
>> This check is done in case we detect the iommu translates MSI
>> (an IOMMU_RESV_MSI window exists). Otherwise the IRQ remapping
>> capability is checked at IOMMU level. Obviously this is a defensive
>> IRQ safety assessment: Assuming there are several MSI controllers
>> in the system and at least one does not implement IRQ remapping,
>> the assignment will be considered as unsafe (even if this controller
>> is not acessible from the assigned devices).
>>
>> The series first patch stems from Robin's branch:
>> http://linux-arm.org/git?p=linux-rm.git;a=shortlog;h=refs/heads/iommu/misc
>>
>>
>> Best Regards
>>
>> Eric
>>
>> Git: complete series available at
>> https://github.com/eauger/linux/tree/v4.10-rc3-reserved-v8
>
> I tested the series on ThunderX with internal 10G VNIC and Intel IXGBE
> NIC. Please feel free to add my:
> Tested-by: Tomasz Nowicki <tomasz.nowicki@caviumnetworks.com>
Many thanks!
Eric
>
> Thanks,
> Tomasz
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 1/4] phy: sun4i-usb: add support for V3s USB PHY
From: Kishon Vijay Abraham I @ 2017-01-16 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170106135624.kbjdvb3wtytfj6ob@lukather>
On Friday 06 January 2017 07:26 PM, Maxime Ripard wrote:
> On Tue, Jan 03, 2017 at 11:25:31PM +0800, Icenowy Zheng wrote:
>> Allwinner V3s come with a USB PHY controller slightly different to other
>> SoCs, with only one PHY.
>>
>> Add support for it.
>>
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
>
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
merged, thanks!
-Kishon
>
> Thanks,
> Maxime
>
^ permalink raw reply
* [RFC PATCH v2 05/10] genirq: export irq_get_percpu_devid_partition to modules
From: Thomas Gleixner @ 2017-01-16 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484323429-15231-6-git-send-email-will.deacon@arm.com>
On Fri, 13 Jan 2017, Will Deacon wrote:
> Any modular driver using cluster-affine PPIs needs to be able to call
> irq_get_percpu_devid_partition so that it can enable the IRQ on the
> correct subset of CPUs.
>
> This patch exports the symbol so that it can be called from within a
> module.
>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> ---
> kernel/irq/irqdesc.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
> index 00bb0aeea1d0..1e6ae73eae59 100644
> --- a/kernel/irq/irqdesc.c
> +++ b/kernel/irq/irqdesc.c
> @@ -856,6 +856,7 @@ int irq_get_percpu_devid_partition(unsigned int irq, struct cpumask *affinity)
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(irq_get_percpu_devid_partition);
Acked-by: Thomas Gleixner <tglx@linutronix.de>
^ 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