* [RESEND PATCH] pinctrl: rockchip: Disable interrupt when changing it's capability
From: JeffyChen @ 2018-05-08 2:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508015623.GA61455@rodete-desktop-imager.corp.google.com>
Hi Brian,
On 05/08/2018 09:56 AM, Brian Norris wrote:
> On Tue, May 08, 2018 at 09:36:24AM +0800, Jeffy Chen wrote:
>> On 05/08/2018 06:15 AM, Brian Norris wrote:
>>> On the other hand...this also implies there may be a race condition
>>> there, where we might lose an interrupt if there is an edge between the
>>> re-configuration of the polarity in rockchip_irq_demux() and the
>>> clearing/handling of the interrupt (handle_edge_irq() ->
>>> chip->irq_ack()). If we have an edge between there, then we might ack
>>> it, but leave the polarity such that we aren't ready for the next
>>> (inverted) edge.
>>
>> if let me guess, the unexpected irq we saw is the hardware trying to avoid
>> losing irq? for example, we set a EDGE_RISING, and the hardware saw the gpio
>> is already high, then though it might lost an irq, so fake one for safe?
>
> I won't pretend to know what the IC designers were doing, but I don't
> think that would resolve the problem I'm talking about. The sequence is
> something like:
> 1. EDGE_BOTH IRQ occurs (e.g., low to high)
> 2. reconfigure polarity in rockchip_irq_demux() (polarity=low)
> 3. continue to handle_edge_irq()
> 4. another HW edge occurs (e.g., high to low)
> 5. handle_edge_irq() (from 3) acks (clears) IRQ (before a subsequent
> rockchip_irq_demux() gets a chance to run and flip the polarity)
> ...
>
> Now the polarity is still low, but the next trigger should be a
> low-to-high edge.
oops, i see the problem.
so what if we do these:
1/ edge irq triggered
2/ read gpio level
3/ handle irq(ack irq)
4/ toggle edge mode(with a while gpio level check)
if the gpio changed in 2/ -> 3/, the 4/ will trigger an irq when writing
GPIO_INT_POLARITY(which is what we are trying to avoid in the set_type case)
but this would not work if i'm wrong about how the HW fake an irq when
changing POLARITY...
or maybe we could just check the gpio status again after
handle_edge_irq, and correct the polarity in this case
>
>> i'll try to confirm it with IC guys.
>
> Brian
>
>
>
^ permalink raw reply
* [PATCH 7/7] drm/mediatek: config component output by device node port
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
We can select output component by decive node port.
Main path default output component is DSI.
External path default output component is DPI.
Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 37 ++++++++++++++++++++++++++++++----
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 4 ++--
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index f4fb86ab7b8d..05333769d862 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -24,6 +24,8 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp.h"
@@ -133,7 +135,7 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
.atomic_commit = mtk_atomic_commit,
};
-static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
+static enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
DDP_COMPONENT_OVL0,
DDP_COMPONENT_RDMA0,
DDP_COMPONENT_COLOR0,
@@ -141,12 +143,12 @@ static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
DDP_COMPONENT_DSI0,
};
-static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
+static enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
DDP_COMPONENT_RDMA1,
DDP_COMPONENT_DPI0,
};
-static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
+static enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
DDP_COMPONENT_OVL0,
DDP_COMPONENT_COLOR0,
DDP_COMPONENT_AAL,
@@ -157,7 +159,7 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
DDP_COMPONENT_PWM0,
};
-static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
+static enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
DDP_COMPONENT_OVL1,
DDP_COMPONENT_COLOR1,
DDP_COMPONENT_GAMMA,
@@ -411,6 +413,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
/* Iterate over sibling DISP function blocks */
for_each_child_of_node(dev->of_node->parent, node) {
+ struct device_node *port, *ep, *remote;
const struct of_device_id *of_id;
enum mtk_ddp_comp_type comp_type;
int comp_id;
@@ -470,6 +473,32 @@ static int mtk_drm_probe(struct platform_device *pdev)
private->ddp_comp[comp_id] = comp;
}
+
+ if (comp_type != MTK_DSI && comp_type != MTK_DPI) {
+ port = of_graph_get_port_by_id(node, 0);
+ if (!port)
+ continue;
+ ep = of_get_child_by_name(port, "endpoint");
+ of_node_put(port);
+ if (!ep)
+ continue;
+ remote = of_graph_get_remote_port_parent(ep);
+ of_node_put(ep);
+ if (!remote)
+ continue;
+ of_id = of_match_node(mtk_ddp_comp_dt_ids, remote);
+ if (!of_id)
+ continue;
+ comp_type = (enum mtk_ddp_comp_type)of_id->data;
+ for (i = 0; i < private->data->main_len - 1; i++)
+ if (private->data->main_path[i] == comp_id)
+ private->data->main_path[i + 1] =
+ mtk_ddp_comp_get_id(node, comp_type);
+ for (i = 0; i < private->data->ext_len - 1; i++)
+ if (private->data->ext_path[i] == comp_id)
+ private->data->ext_path[i + 1] =
+ mtk_ddp_comp_get_id(node, comp_type);
+ }
}
if (!private->mutex_node) {
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index c3378c452c0a..2bcba8eb06f4 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -29,9 +29,9 @@ struct drm_property;
struct regmap;
struct mtk_mmsys_driver_data {
- const enum mtk_ddp_comp_id *main_path;
+ enum mtk_ddp_comp_id *main_path;
unsigned int main_len;
- const enum mtk_ddp_comp_id *ext_path;
+ enum mtk_ddp_comp_id *ext_path;
unsigned int ext_len;
bool shadow_register;
};
--
2.12.5
^ permalink raw reply related
* [PATCH 6/7] drm/mediatek: add a error return value when clock driver has been prepared
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
DRM driver get the comp->clk by of_clk_get(), we only
assign NULL to comp->clk when error happened, but do
not return the error number.
Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 4672317e3ad1..d38a5303f8fc 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -283,7 +283,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
comp->irq = of_irq_get(node, 0);
comp->clk = of_clk_get(node, 0);
if (IS_ERR(comp->clk))
- comp->clk = NULL;
+ return PTR_ERR(comp->clk);
/* Only DMA capable components need the LARB property */
comp->larb_dev = NULL;
--
2.12.5
^ permalink raw reply related
* [PATCH 5/7] drm/mediatek: implement connection from BLS to DPI0
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
Modify display driver to support connection from BLS to DPI.
Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index 8130f3dab661..289a68c6731f 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -35,6 +35,7 @@
#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030
#define DISP_REG_CONFIG_OUT_SEL 0x04c
#define DISP_REG_CONFIG_DSI_SEL 0x050
+#define DISP_REG_CONFIG_DPI_SEL 0x064
#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n))
#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
@@ -84,7 +85,10 @@
#define OVL_MOUT_EN_RDMA 0x1
#define BLS_TO_DSI_RDMA1_TO_DPI1 0x8
+#define BLS_TO_DPI_RDMA1_TO_DSI 0x2
#define DSI_SEL_IN_BLS 0x0
+#define DPI_SEL_IN_BLS 0x0
+#define DSI_SEL_IN_RDMA 0x1
struct mtk_disp_mutex {
int id;
@@ -189,9 +193,17 @@ static void mtk_ddp_sout_sel(void __iomem *config_regs,
enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next)
{
- if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0)
+ if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) {
writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1,
config_regs + DISP_REG_CONFIG_OUT_SEL);
+ } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DPI0) {
+ writel_relaxed(BLS_TO_DPI_RDMA1_TO_DSI,
+ config_regs + DISP_REG_CONFIG_OUT_SEL);
+ writel_relaxed(DSI_SEL_IN_RDMA,
+ config_regs + DISP_REG_CONFIG_DSI_SEL);
+ writel_relaxed(DPI_SEL_IN_BLS,
+ config_regs + DISP_REG_CONFIG_DPI_SEL);
+ }
}
void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
--
2.12.5
^ permalink raw reply related
* [PATCH 4/7] drm/mediatek: add hdmi driver for different hardware
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
From: chunhui dai <chunhui.dai@mediatek.com>
This patch adds hdmi dirver suppot for both MT2701 and MT7623.
And also support other (existing or future) chips that use
the same binding and driver.
Signed-off-by: Chunhui Dai <chunhui.dai@mediatek.com>
---
drivers/gpu/drm/mediatek/Makefile | 4 +-
drivers/gpu/drm/mediatek/mtk_hdmi.c | 88 +++++--
drivers/gpu/drm/mediatek/mtk_hdmi.h | 28 +++
drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 157 +++++++++++++
drivers/gpu/drm/mediatek/mtk_hdmi_regs.h | 1 +
drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 307 +++++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 129 +----------
7 files changed, 566 insertions(+), 148 deletions(-)
create mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
create mode 100644 drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index ce83c396a742..44464893c1cb 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
mediatek-drm-hdmi-objs := mtk_cec.o \
mtk_hdmi.o \
mtk_hdmi_ddc.o \
- mtk_mt8173_hdmi_phy.o
+ mtk_mt2701_hdmi_phy.o \
+ mtk_mt8173_hdmi_phy.o \
+ mtk_hdmi_phy.o
obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 59a11026dceb..accafd95d6a8 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -233,6 +233,7 @@ static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black)
static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable)
{
struct arm_smccc_res res;
+ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(hdmi->phy);
/*
* MT8173 HDMI hardware has an output control bit to enable/disable HDMI
@@ -240,8 +241,13 @@ static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable)
* The ARM trusted firmware provides an API for the HDMI driver to set
* this control bit to enable HDMI output in supervisor mode.
*/
- arm_smccc_smc(MTK_SIP_SET_AUTHORIZED_SECURE_REG, 0x14000904, 0x80000000,
- 0, 0, 0, 0, 0, &res);
+ if (hdmi_phy->conf && hdmi_phy->conf->tz_enabled)
+ arm_smccc_smc(MTK_SIP_SET_AUTHORIZED_SECURE_REG, 0x14000904,
+ 0x80000000, 0, 0, 0, 0, 0, &res);
+ else
+ regmap_update_bits(hdmi->sys_regmap,
+ hdmi->sys_offset + HDMI_SYS_CFG20,
+ HDMI_PSECUR_EN, enable ? 0 : HDMI_PSECUR_EN);
regmap_update_bits(hdmi->sys_regmap, hdmi->sys_offset + HDMI_SYS_CFG20,
HDMI_PCLK_FREE_RUN, enable ? HDMI_PCLK_FREE_RUN : 0);
@@ -1437,6 +1443,7 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
struct platform_device *cec_pdev;
struct regmap *regmap;
struct resource *mem;
+ const char *phy_name;
int ret;
ret = mtk_hdmi_get_all_clk(hdmi, np);
@@ -1445,9 +1452,20 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
return ret;
}
+ ret = of_property_read_string(np, "phy-names", &phy_name);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read phy-names: %d\n", ret);
+ return ret;
+ }
+ hdmi->phy = devm_phy_get(dev, phy_name);
+ if (IS_ERR(hdmi->phy)) {
+ ret = PTR_ERR(hdmi->phy);
+ dev_err(dev, "Failed to get HDMI PHY: %d\n", ret);
+ return ret;
+ }
+
/* The CEC module handles HDMI hotplug detection */
- cec_np = of_find_compatible_node(np->parent, NULL,
- "mediatek,mt8173-cec");
+ cec_np = of_parse_phandle(np, "cec", 0);
if (!cec_np) {
dev_err(dev, "Failed to find CEC node\n");
return -EINVAL;
@@ -1486,8 +1504,14 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
return PTR_ERR(hdmi->regs);
remote = of_graph_get_remote_node(np, 1, 0);
- if (!remote)
- return -EINVAL;
+ if (!remote) {
+ i2c_np = of_parse_phandle(np, "ddc-i2c-bus", 0);
+ if (!i2c_np) {
+ dev_err(dev, "Failed to find ddc-i2c-bus node\n");
+ return -EINVAL;
+ }
+ goto find_ddc_adpt;
+ }
if (!of_device_is_compatible(remote, "hdmi-connector")) {
hdmi->next_bridge = of_drm_find_bridge(remote);
@@ -1507,6 +1531,7 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
}
of_node_put(remote);
+find_ddc_adpt:
hdmi->ddc_adpt = of_find_i2c_adapter_by_node(i2c_np);
if (!hdmi->ddc_adpt) {
dev_err(dev, "Failed to get ddc i2c adapter by node\n");
@@ -1575,6 +1600,11 @@ static int mtk_hdmi_audio_hw_params(struct device *dev, void *data,
hdmi_params.aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
hdmi_params.aud_mclk = HDMI_AUD_MCLK_128FS;
break;
+ case HDMI_SPDIF:
+ hdmi_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
+ hdmi_params.aud_sampe_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+ hdmi_params.aud_input_type = HDMI_AUD_INPUT_SPDIF;
+ break;
default:
dev_err(hdmi->dev, "%s: Invalid DAI format %d\n", __func__,
daifmt->fmt);
@@ -1650,15 +1680,15 @@ static void mtk_hdmi_register_audio_driver(struct device *dev)
.max_i2s_channels = 2,
.i2s = 1,
};
- struct platform_device *pdev;
+ static struct platform_device *pdev;
- pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
- PLATFORM_DEVID_AUTO, &codec_data,
- sizeof(codec_data));
- if (IS_ERR(pdev))
+ if (!pdev) {
+ pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_NONE, &codec_data,
+ sizeof(codec_data));
+ DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME);
+ }
return;
-
- DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME);
}
static int mtk_drm_hdmi_probe(struct platform_device *pdev)
@@ -1672,18 +1702,12 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
return -ENOMEM;
hdmi->dev = dev;
+ mtk_hdmi_register_audio_driver(dev);
ret = mtk_hdmi_dt_parse_pdata(hdmi, pdev);
if (ret)
return ret;
- hdmi->phy = devm_phy_get(dev, "hdmi");
- if (IS_ERR(hdmi->phy)) {
- ret = PTR_ERR(hdmi->phy);
- dev_err(dev, "Failed to get HDMI PHY: %d\n", ret);
- return ret;
- }
-
platform_set_drvdata(pdev, hdmi);
ret = mtk_hdmi_output_init(hdmi);
@@ -1692,8 +1716,6 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
return ret;
}
- mtk_hdmi_register_audio_driver(dev);
-
hdmi->bridge.funcs = &mtk_hdmi_bridge_funcs;
hdmi->bridge.of_node = pdev->dev.of_node;
drm_bridge_add(&hdmi->bridge);
@@ -1704,7 +1726,6 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
goto err_bridge_remove;
}
- dev_dbg(dev, "mediatek hdmi probe success\n");
return 0;
err_bridge_remove:
@@ -1773,8 +1794,25 @@ static struct platform_driver * const mtk_hdmi_drivers[] = {
static int __init mtk_hdmitx_init(void)
{
- return platform_register_drivers(mtk_hdmi_drivers,
- ARRAY_SIZE(mtk_hdmi_drivers));
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mtk_hdmi_drivers); i++) {
+ ret = platform_driver_register(mtk_hdmi_drivers[i]);
+ if (ret < 0) {
+ pr_err("Failed to register %s driver: %d\n",
+ mtk_hdmi_drivers[i]->driver.name, ret);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0)
+ platform_driver_unregister(mtk_hdmi_drivers[i]);
+
+ return ret;
}
static void __exit mtk_hdmitx_exit(void)
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.h b/drivers/gpu/drm/mediatek/mtk_hdmi.h
index 6371b3de1ff6..a4546b83329f 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.h
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.h
@@ -13,11 +13,39 @@
*/
#ifndef _MTK_HDMI_CTRL_H
#define _MTK_HDMI_CTRL_H
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+
+struct mtk_hdmi_phy_conf {
+ bool tz_enabled;
+ const struct clk_ops *hdmi_phy_clk_ops;
+ const struct phy_ops *hdmi_phy_dev_ops;
+};
+
+struct mtk_hdmi_phy {
+ void __iomem *regs;
+ struct device *dev;
+ struct mtk_hdmi_phy_conf *conf;
+ struct clk *pll;
+ struct clk_hw pll_hw;
+ unsigned long pll_rate;
+ unsigned char drv_imp_clk;
+ unsigned char drv_imp_d2;
+ unsigned char drv_imp_d1;
+ unsigned char drv_imp_d0;
+ unsigned int ibias;
+ unsigned int ibias_up;
+};
struct platform_driver;
extern struct platform_driver mtk_cec_driver;
extern struct platform_driver mtk_hdmi_ddc_driver;
extern struct platform_driver mtk_hdmi_phy_driver;
+extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf;
+extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf;
+
#endif /* _MTK_HDMI_CTRL_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
new file mode 100644
index 000000000000..325790abd469
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Jie Qiu <jie.qiu@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/phy/phy.h>
+#include "mtk_hdmi.h"
+
+static void mtk_hdmi_phy_clk_get_ops(struct mtk_hdmi_phy *hdmi_phy,
+ const struct clk_ops **ops)
+{
+ if (hdmi_phy && hdmi_phy->conf && hdmi_phy->conf->hdmi_phy_clk_ops)
+ *ops = hdmi_phy->conf->hdmi_phy_clk_ops;
+ else
+ dev_err(hdmi_phy->dev, "Failed to get clk ops of phy\n");
+}
+
+static const struct phy_ops *
+mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy)
+{
+ if (hdmi_phy && hdmi_phy->conf && hdmi_phy->conf->hdmi_phy_dev_ops)
+ return hdmi_phy->conf->hdmi_phy_dev_ops;
+ dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n");
+ return NULL;
+}
+
+static int mtk_hdmi_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_hdmi_phy *hdmi_phy;
+ struct resource *mem;
+ struct clk *ref_clk;
+ const char *ref_clk_name;
+ struct clk_init_data clk_init = {
+ .num_parents = 1,
+ .parent_names = (const char * const *)&ref_clk_name,
+ .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
+ };
+
+ struct phy *phy;
+ struct phy_provider *phy_provider;
+ int ret;
+
+ hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
+ if (!hdmi_phy)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hdmi_phy->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(hdmi_phy->regs)) {
+ ret = PTR_ERR(hdmi_phy->regs);
+ dev_err(dev, "Failed to get memory resource: %d\n", ret);
+ return ret;
+ }
+
+ ref_clk = devm_clk_get(dev, "pll_ref");
+ if (IS_ERR(ref_clk)) {
+ ret = PTR_ERR(ref_clk);
+ dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n",
+ ret);
+ return ret;
+ }
+ ref_clk_name = __clk_get_name(ref_clk);
+
+ ret = of_property_read_string(dev->of_node, "clock-output-names",
+ &clk_init.name);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read clock-output-names: %d\n", ret);
+ return ret;
+ }
+
+ hdmi_phy->dev = dev;
+ hdmi_phy->conf =
+ (struct mtk_hdmi_phy_conf *)of_device_get_match_data(dev);
+ mtk_hdmi_phy_clk_get_ops(hdmi_phy, &clk_init.ops);
+ hdmi_phy->pll_hw.init = &clk_init;
+ hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
+ if (IS_ERR(hdmi_phy->pll)) {
+ ret = PTR_ERR(hdmi_phy->pll);
+ dev_err(dev, "Failed to register PLL: %d\n", ret);
+ return ret;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
+ &hdmi_phy->ibias);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret);
+ return ret;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
+ &hdmi_phy->ibias_up);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
+ hdmi_phy->drv_imp_clk = 0x30;
+ hdmi_phy->drv_imp_d2 = 0x30;
+ hdmi_phy->drv_imp_d1 = 0x30;
+ hdmi_phy->drv_imp_d0 = 0x30;
+
+ phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy));
+ if (IS_ERR(phy)) {
+ dev_err(dev, "Failed to create HDMI PHY\n");
+ return PTR_ERR(phy);
+ }
+ phy_set_drvdata(phy, hdmi_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider)) {
+ dev_err(dev, "Failed to register HDMI PHY\n");
+ return PTR_ERR(phy_provider);
+ }
+
+ return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
+ hdmi_phy->pll);
+}
+
+static int mtk_hdmi_phy_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id mtk_hdmi_phy_match[] = {
+ { .compatible = "mediatek,mt2701-hdmi-phy",
+ .data = &mtk_hdmi_phy_2701_conf,
+ },
+ { .compatible = "mediatek,mt8173-hdmi-phy",
+ .data = &mtk_hdmi_phy_8173_conf,
+ },
+ {},
+};
+
+struct platform_driver mtk_hdmi_phy_driver = {
+ .probe = mtk_hdmi_phy_probe,
+ .remove = mtk_hdmi_phy_remove,
+ .driver = {
+ .name = "mediatek-hdmi-phy",
+ .of_match_table = mtk_hdmi_phy_match,
+ },
+};
+
+MODULE_DESCRIPTION("MediaTek HDMI PHY Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_regs.h b/drivers/gpu/drm/mediatek/mtk_hdmi_regs.h
index a5cb07d12c9c..e53c6646571c 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_regs.h
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_regs.h
@@ -227,6 +227,7 @@
#define DEEP_COLOR_EN BIT(0)
#define HDMI_AUDIO_TEST_SEL BIT(8)
#define HDMI2P0_EN BIT(11)
+#define HDMI_PSECUR_EN BIT(15)
#define HDMI_OUT_FIFO_EN BIT(16)
#define HDMI_OUT_FIFO_CLK_INV BIT(17)
#define MHL_MODE_ON BIT(28)
diff --git a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c
new file mode 100644
index 000000000000..8af5e6c1aecc
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *Copyright (c) 2018 MediaTek Inc.
+ *Author: Chunhui Dai <chunhui.dai@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/phy/phy.h>
+#include "mtk_hdmi.h"
+
+#define HDMI_CON0 0x00
+#define RG_HDMITX_DRV_IBIAS (0)
+#define RG_HDMITX_DRV_IBIAS_MASK (0x3F << 0)
+#define RG_HDMITX_EN_SER (12)
+#define RG_HDMITX_EN_SER_MASK (0x0F << 12)
+#define RG_HDMITX_EN_SLDO (16)
+#define RG_HDMITX_EN_SLDO_MASK (0x0F << 16)
+#define RG_HDMITX_EN_PRED (20)
+#define RG_HDMITX_EN_PRED_MASK (0x0F << 20)
+#define RG_HDMITX_EN_IMP (24)
+#define RG_HDMITX_EN_IMP_MASK (0x0F << 24)
+#define RG_HDMITX_EN_DRV (28)
+#define RG_HDMITX_EN_DRV_MASK (0x0F << 28)
+
+#define HDMI_CON1 0x04
+#define RG_HDMITX_PRED_IBIAS (18)
+#define RG_HDMITX_PRED_IBIAS_MASK (0x0F << 18)
+#define RG_HDMITX_PRED_IMP (0x01 << 22)
+#define RG_HDMITX_DRV_IMP (26)
+#define RG_HDMITX_DRV_IMP_MASK (0x3F << 26)
+
+#define HDMI_CON2 0x08
+#define RG_HDMITX_EN_TX_CKLDO (0x01 << 0)
+#define RG_HDMITX_EN_TX_POSDIV (0x01 << 1)
+#define RG_HDMITX_TX_POSDIV (3)
+#define RG_HDMITX_TX_POSDIV_MASK (0x03 << 3)
+#define RG_HDMITX_EN_MBIAS (0x01 << 6)
+#define RG_HDMITX_MBIAS_LPF_EN (0x01 << 7)
+
+#define HDMI_CON4 0x10
+#define RG_HDMITX_RESERVE_MASK (0xFFFFFFFF << 0)
+
+#define HDMI_CON6 0x18
+#define RG_HTPLL_BR (0)
+#define RG_HTPLL_BR_MASK (0x03 << 0)
+#define RG_HTPLL_BC (2)
+#define RG_HTPLL_BC_MASK (0x03 << 2)
+#define RG_HTPLL_BP (4)
+#define RG_HTPLL_BP_MASK (0x0F << 4)
+#define RG_HTPLL_IR (8)
+#define RG_HTPLL_IR_MASK (0x0F << 8)
+#define RG_HTPLL_IC (12)
+#define RG_HTPLL_IC_MASK (0x0F << 12)
+#define RG_HTPLL_POSDIV (16)
+#define RG_HTPLL_POSDIV_MASK (0x03 << 16)
+#define RG_HTPLL_PREDIV (18)
+#define RG_HTPLL_PREDIV_MASK (0x03 << 18)
+#define RG_HTPLL_FBKSEL (20)
+#define RG_HTPLL_FBKSEL_MASK (0x03 << 20)
+#define RG_HTPLL_RLH_EN (0x01 << 22)
+#define RG_HTPLL_FBKDIV (24)
+#define RG_HTPLL_FBKDIV_MASK (0x7F << 24)
+#define RG_HTPLL_EN (0x01 << 31)
+
+#define HDMI_CON7 0x1c
+#define RG_HTPLL_AUTOK_EN (0x01 << 23)
+#define RG_HTPLL_DIVEN (28)
+#define RG_HTPLL_DIVEN_MASK (0x07 << 28)
+
+static inline struct mtk_hdmi_phy *to_mtk_hdmi_pll(struct clk_hw *hw)
+{
+ return container_of(hw, struct mtk_hdmi_phy, pll_hw);
+}
+
+static inline void mtk_hdmi_pll_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 tmp = readl(hdmi_phy->regs + offset) & ~mask;
+
+ tmp |= (val & mask);
+ writel(tmp, hdmi_phy->regs + offset);
+}
+
+static int mtk_hdmi_pll_enable(struct clk_hw *hw)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN,
+ RG_HTPLL_AUTOK_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_RLH_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x3 << RG_HTPLL_POSDIV),
+ RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS,
+ RG_HDMITX_EN_MBIAS);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, RG_HTPLL_EN, RG_HTPLL_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO,
+ RG_HDMITX_EN_TX_CKLDO);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_SLDO),
+ RG_HDMITX_EN_SLDO_MASK);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN,
+ RG_HDMITX_MBIAS_LPF_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV,
+ RG_HDMITX_EN_TX_POSDIV);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_SER),
+ RG_HDMITX_EN_SER_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_PRED),
+ RG_HDMITX_EN_PRED_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_DRV),
+ RG_HDMITX_EN_DRV_MASK);
+ usleep_range(80, 100);
+ return 0;
+}
+
+static void mtk_hdmi_pll_disable(struct clk_hw *hw)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_DRV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_PRED_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_SER_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_TX_POSDIV);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_MBIAS_LPF_EN);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_SLDO_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_TX_CKLDO);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_EN);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_MBIAS);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_RLH_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, 0, RG_HTPLL_AUTOK_EN);
+ usleep_range(80, 100);
+}
+
+static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+ u32 pos_div;
+
+ if (rate <= 64000000)
+ pos_div = 3;
+ else if (rate <= 12800000)
+ pos_div = 1;
+ else
+ pos_div = 1;
+
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x3 << RG_HTPLL_PREDIV),
+ RG_HTPLL_PREDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x3 << RG_HTPLL_POSDIV),
+ RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IC),
+ RG_HTPLL_IC_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IR),
+ RG_HTPLL_IR_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, (pos_div << RG_HDMITX_TX_POSDIV),
+ RG_HDMITX_TX_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (1 << RG_HTPLL_FBKSEL),
+ RG_HTPLL_FBKSEL_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (19 << RG_HTPLL_FBKDIV),
+ RG_HTPLL_FBKDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, (0x2 << RG_HTPLL_DIVEN),
+ RG_HTPLL_DIVEN_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0xc << RG_HTPLL_BP),
+ RG_HTPLL_BP_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x2 << RG_HTPLL_BC),
+ RG_HTPLL_BC_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_BR),
+ RG_HTPLL_BR_MASK);
+
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON1, 0, RG_HDMITX_PRED_IMP);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON1, (0x3 << RG_HDMITX_PRED_IBIAS),
+ RG_HDMITX_PRED_IBIAS_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0x0 << RG_HDMITX_EN_IMP),
+ RG_HDMITX_EN_IMP_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON1, (0x28 << RG_HDMITX_DRV_IMP),
+ RG_HDMITX_DRV_IMP_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON4, 0x28, RG_HDMITX_RESERVE_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xa << RG_HDMITX_DRV_IBIAS),
+ RG_HDMITX_DRV_IBIAS_MASK);
+ return 0;
+}
+
+static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+
+ hdmi_phy->pll_rate = rate;
+ return rate;
+}
+
+static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+
+ return hdmi_phy->pll_rate;
+}
+
+static const struct clk_ops mtk_hdmi_phy_pll_ops = {
+ .enable = mtk_hdmi_pll_enable,
+ .disable = mtk_hdmi_pll_disable,
+ .set_rate = mtk_hdmi_pll_set_rate,
+ .round_rate = mtk_hdmi_pll_round_rate,
+ .recalc_rate = mtk_hdmi_pll_recalc_rate,
+};
+
+static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy)
+{
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN,
+ RG_HTPLL_AUTOK_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_RLH_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x3 << RG_HTPLL_POSDIV),
+ RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS,
+ RG_HDMITX_EN_MBIAS);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, RG_HTPLL_EN, RG_HTPLL_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO,
+ RG_HDMITX_EN_TX_CKLDO);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_SLDO),
+ RG_HDMITX_EN_SLDO_MASK);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN,
+ RG_HDMITX_MBIAS_LPF_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV,
+ RG_HDMITX_EN_TX_POSDIV);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_SER),
+ RG_HDMITX_EN_SER_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_PRED),
+ RG_HDMITX_EN_PRED_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_DRV),
+ RG_HDMITX_EN_DRV_MASK);
+ usleep_range(80, 100);
+}
+
+static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy)
+{
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_DRV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_PRED_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_SER_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_TX_POSDIV);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_MBIAS_LPF_EN);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_SLDO_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_TX_CKLDO);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_EN);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_MBIAS);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_RLH_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, 0, RG_HTPLL_AUTOK_EN);
+ usleep_range(80, 100);
+}
+
+static int mtk_hdmi_phy_power_on(struct phy *phy)
+{
+ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+ int ret;
+
+ ret = clk_prepare_enable(hdmi_phy->pll);
+ if (ret < 0)
+ return ret;
+
+ mtk_hdmi_phy_enable_tmds(hdmi_phy);
+
+ return 0;
+}
+
+static int mtk_hdmi_phy_power_off(struct phy *phy)
+{
+ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ mtk_hdmi_phy_disable_tmds(hdmi_phy);
+ clk_disable_unprepare(hdmi_phy->pll);
+
+ return 0;
+}
+
+static const struct phy_ops mtk_hdmi_phy_dev_ops = {
+ .power_on = mtk_hdmi_phy_power_on,
+ .power_off = mtk_hdmi_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf = {
+ .tz_enabled = false,
+ .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops,
+ .hdmi_phy_dev_ops = &mtk_hdmi_phy_dev_ops,
+};
+
+MODULE_AUTHOR("Chunhui Dai <chunhui.dai@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek HDMI PHY Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
index 51cb9cfb6646..1a35fdd405d8 100644
--- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
+++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
@@ -21,6 +21,7 @@
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/types.h>
+#include "mtk_hdmi.h"
#define HDMI_CON0 0x00
#define RG_HDMITX_PLL_EN BIT(31)
@@ -123,20 +124,6 @@
#define RGS_HDMITX_5T1_EDG (0xf << 4)
#define RGS_HDMITX_PLUG_TST BIT(0)
-struct mtk_hdmi_phy {
- void __iomem *regs;
- struct device *dev;
- struct clk *pll;
- struct clk_hw pll_hw;
- unsigned long pll_rate;
- u8 drv_imp_clk;
- u8 drv_imp_d2;
- u8 drv_imp_d1;
- u8 drv_imp_d0;
- u32 ibias;
- u32 ibias_up;
-};
-
static const u8 PREDIV[3][4] = {
{0x0, 0x0, 0x0, 0x0}, /* 27Mhz */
{0x1, 0x1, 0x1, 0x1}, /* 74Mhz */
@@ -367,7 +354,7 @@ static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
return hdmi_phy->pll_rate;
}
-static const struct clk_ops mtk_hdmi_pll_ops = {
+static const struct clk_ops mtk_hdmi_phy_pll_ops = {
.prepare = mtk_hdmi_pll_prepare,
.unprepare = mtk_hdmi_pll_unprepare,
.set_rate = mtk_hdmi_pll_set_rate,
@@ -414,118 +401,16 @@ static int mtk_hdmi_phy_power_off(struct phy *phy)
return 0;
}
-static const struct phy_ops mtk_hdmi_phy_ops = {
+static const struct phy_ops mtk_hdmi_phy_dev_ops = {
.power_on = mtk_hdmi_phy_power_on,
.power_off = mtk_hdmi_phy_power_off,
.owner = THIS_MODULE,
};
-static int mtk_hdmi_phy_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mtk_hdmi_phy *hdmi_phy;
- struct resource *mem;
- struct clk *ref_clk;
- const char *ref_clk_name;
- struct clk_init_data clk_init = {
- .ops = &mtk_hdmi_pll_ops,
- .num_parents = 1,
- .parent_names = (const char * const *)&ref_clk_name,
- .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
- };
- struct phy *phy;
- struct phy_provider *phy_provider;
- int ret;
-
- hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
- if (!hdmi_phy)
- return -ENOMEM;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi_phy->regs = devm_ioremap_resource(dev, mem);
- if (IS_ERR(hdmi_phy->regs)) {
- ret = PTR_ERR(hdmi_phy->regs);
- dev_err(dev, "Failed to get memory resource: %d\n", ret);
- return ret;
- }
-
- ref_clk = devm_clk_get(dev, "pll_ref");
- if (IS_ERR(ref_clk)) {
- ret = PTR_ERR(ref_clk);
- dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n",
- ret);
- return ret;
- }
- ref_clk_name = __clk_get_name(ref_clk);
-
- ret = of_property_read_string(dev->of_node, "clock-output-names",
- &clk_init.name);
- if (ret < 0) {
- dev_err(dev, "Failed to read clock-output-names: %d\n", ret);
- return ret;
- }
-
- hdmi_phy->pll_hw.init = &clk_init;
- hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
- if (IS_ERR(hdmi_phy->pll)) {
- ret = PTR_ERR(hdmi_phy->pll);
- dev_err(dev, "Failed to register PLL: %d\n", ret);
- return ret;
- }
-
- ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
- &hdmi_phy->ibias);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret);
- return ret;
- }
-
- ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
- &hdmi_phy->ibias_up);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret);
- return ret;
- }
-
- dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
- hdmi_phy->drv_imp_clk = 0x30;
- hdmi_phy->drv_imp_d2 = 0x30;
- hdmi_phy->drv_imp_d1 = 0x30;
- hdmi_phy->drv_imp_d0 = 0x30;
-
- phy = devm_phy_create(dev, NULL, &mtk_hdmi_phy_ops);
- if (IS_ERR(phy)) {
- dev_err(dev, "Failed to create HDMI PHY\n");
- return PTR_ERR(phy);
- }
- phy_set_drvdata(phy, hdmi_phy);
-
- phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
- hdmi_phy->dev = dev;
- return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
- hdmi_phy->pll);
-}
-
-static int mtk_hdmi_phy_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-static const struct of_device_id mtk_hdmi_phy_match[] = {
- { .compatible = "mediatek,mt8173-hdmi-phy", },
- {},
-};
-
-struct platform_driver mtk_hdmi_phy_driver = {
- .probe = mtk_hdmi_phy_probe,
- .remove = mtk_hdmi_phy_remove,
- .driver = {
- .name = "mediatek-hdmi-phy",
- .of_match_table = mtk_hdmi_phy_match,
- },
+struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf = {
+ .tz_enabled = true,
+ .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops,
+ .hdmi_phy_dev_ops = &mtk_hdmi_phy_dev_ops,
};
MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>");
--
2.12.5
^ permalink raw reply related
* [PATCH 3/7] drm/mediatek: add dpi driver for mt2701 and mt7623
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
From: chunhui dai <chunhui.dai@mediatek.com>
This patch adds dpi dirver suppot for both mt2701 and mt7623.
And also support other (existing or future) chips that use
the same binding and driver.
Signed-off-by: chunhui dai <chunhui.dai@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 24 ++++++++++++++++++++++--
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 +
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 2b8b34c72697..e1af1d0d213d 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -640,8 +640,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
}
drm_encoder_helper_add(&dpi->encoder, &mtk_dpi_encoder_helper_funcs);
- /* Currently DPI0 is fixed to be driven by OVL1 */
- dpi->encoder.possible_crtcs = BIT(1);
+ dpi->encoder.possible_crtcs = BIT(0) | BIT(1);
dpi->encoder.bridge->encoder = &dpi->encoder;
ret = drm_bridge_attach(&dpi->encoder, dpi->encoder.bridge, NULL);
if (ret) {
@@ -690,12 +689,33 @@ static unsigned int mt8173_calculate_factor(int clock)
return 2 * 3;
}
+static unsigned int mt2701_calculate_factor(int clock)
+{
+ if (clock <= 64000)
+ return 16;
+ else if (clock <= 128000)
+ return 8;
+ else if (clock <= 256000)
+ return 4;
+ else
+ return 2;
+}
+
static const struct mtk_dpi_conf mt8173_conf = {
.cal_factor = mt8173_calculate_factor,
.reg_h_fre_con = 0xe0,
};
+static const struct mtk_dpi_conf mt2701_conf = {
+ .cal_factor = mt2701_calculate_factor,
+ .reg_h_fre_con = 0xb0,
+ .edge_sel_en = true,
+};
+
static const struct of_device_id mtk_dpi_of_ids[] = {
+ { .compatible = "mediatek,mt2701-dpi",
+ .data = &mt2701_conf,
+ },
{ .compatible = "mediatek,mt8173-dpi",
.data = &mt8173_conf,
},
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index a2ca90fc403c..f4fb86ab7b8d 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -372,6 +372,7 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
{ .compatible = "mediatek,mt8173-disp-ufoe", .data = (void *)MTK_DISP_UFOE },
{ .compatible = "mediatek,mt2701-dsi", .data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8173-dsi", .data = (void *)MTK_DSI },
+ { .compatible = "mediatek,mt2701-dpi", .data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8173-dpi", .data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
--
2.12.5
^ permalink raw reply related
* [PATCH 2/7] drm/mediatek: fix to get right bridge for dpi encoder
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
From: chunhui dai <chunhui.dai@mediatek.com>
1, dpi is an encoder, there is an bridge in the struct
of decoder, we could use it.
2, using of_graph_get_remote_port_parent to get right
bridge in device tree.
Signed-off-by: chunhui dai <chunhui.dai@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 0a44ab175422..2b8b34c72697 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -63,7 +63,6 @@ enum mtk_dpi_out_color_format {
struct mtk_dpi {
struct mtk_ddp_comp ddp_comp;
struct drm_encoder encoder;
- struct drm_bridge *bridge;
void __iomem *regs;
struct device *dev;
struct clk *engine_clk;
@@ -643,8 +642,8 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
/* Currently DPI0 is fixed to be driven by OVL1 */
dpi->encoder.possible_crtcs = BIT(1);
-
- ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
+ dpi->encoder.bridge->encoder = &dpi->encoder;
+ ret = drm_bridge_attach(&dpi->encoder, dpi->encoder.bridge, NULL);
if (ret) {
dev_err(dev, "Failed to attach bridge: %d\n", ret);
goto err_cleanup;
@@ -709,7 +708,7 @@ static int mtk_dpi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mtk_dpi *dpi;
struct resource *mem;
- struct device_node *bridge_node;
+ struct device_node *ep, *bridge_node;
int comp_id;
const struct of_device_id *match;
int ret;
@@ -759,15 +758,21 @@ static int mtk_dpi_probe(struct platform_device *pdev)
return -EINVAL;
}
- bridge_node = of_graph_get_remote_node(dev->of_node, 0, 0);
- if (!bridge_node)
+ ep = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (ep) {
+ bridge_node = of_graph_get_remote_port_parent(ep);
+ of_node_put(ep);
+ }
+ if (!bridge_node) {
+ dev_err(dev, "Failed to find bridge node\n");
return -ENODEV;
+ }
dev_info(dev, "Found bridge node: %pOF\n", bridge_node);
- dpi->bridge = of_drm_find_bridge(bridge_node);
+ dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
of_node_put(bridge_node);
- if (!dpi->bridge)
+ if (!dpi->encoder.bridge)
return -EPROBE_DEFER;
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
--
2.12.5
^ permalink raw reply related
* [PATCH 1/7] drm/mediatek: move dpi private data to device
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
From: chunhui dai <chunhui.dai@mediatek.com>
move colck factor and edge enable setting to private data.
Signed-off-by: chunhui dai <chunhui.dai@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 80 ++++++++++++++++++++++++++-------
drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 2 +-
2 files changed, 65 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index e80a603e5fb0..0a44ab175422 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -71,11 +71,13 @@ struct mtk_dpi {
struct clk *tvd_clk;
int irq;
struct drm_display_mode mode;
+ const struct mtk_dpi_conf *conf;
enum mtk_dpi_out_color_format color_format;
enum mtk_dpi_out_yc_map yc_map;
enum mtk_dpi_out_bit_num bit_num;
enum mtk_dpi_out_channel_swap channel_swap;
bool power_sta;
+ int refcount;
u8 power_ctl;
};
@@ -115,6 +117,12 @@ struct mtk_dpi_yc_limit {
u16 c_bottom;
};
+struct mtk_dpi_conf {
+ unsigned int (*cal_factor)(int clock);
+ const u32 reg_h_fre_con;
+ bool edge_sel_en;
+};
+
static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
{
u32 tmp = readl(dpi->regs + offset) & ~mask;
@@ -340,7 +348,13 @@ static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable)
static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi)
{
- mtk_dpi_mask(dpi, DPI_H_FRE_CON, H_FRE_2N, H_FRE_2N);
+ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N);
+}
+
+static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi)
+{
+ if (dpi->conf->edge_sel_en)
+ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN);
}
static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
@@ -368,6 +382,12 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
{
+ if (WARN_ON(dpi->refcount == 0))
+ return;
+
+ if (--dpi->refcount != 0)
+ return;
+
dpi->power_ctl &= ~pctl;
if ((dpi->power_ctl & DPI_POWER_START) ||
@@ -387,14 +407,17 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
{
int ret;
+ if (++dpi->refcount != 1)
+ return 0;
+
dpi->power_ctl |= pctl;
if (!(dpi->power_ctl & DPI_POWER_START) &&
!(dpi->power_ctl & DPI_POWER_ENABLE))
- return 0;
+ goto err_refcount;
if (dpi->power_sta)
- return 0;
+ goto err_refcount;
ret = clk_prepare_enable(dpi->engine_clk);
if (ret) {
@@ -416,6 +439,8 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
clk_disable_unprepare(dpi->engine_clk);
err_eng:
dpi->power_ctl &= ~pctl;
+err_refcount:
+ dpi->refcount--;
return ret;
}
@@ -433,16 +458,13 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
unsigned long pll_rate;
unsigned int factor;
+ if (!dpi) {
+ dev_err(dpi->dev, "invalid argument\n");
+ return -EINVAL;
+ }
/* let pll_rate can fix the valid range of tvdpll (1G~2GHz) */
pix_rate = 1000UL * mode->clock;
- if (mode->clock <= 27000)
- factor = 16 * 3;
- else if (mode->clock <= 84000)
- factor = 8 * 3;
- else if (mode->clock <= 167000)
- factor = 4 * 3;
- else
- factor = 2 * 3;
+ factor = dpi->conf->cal_factor(mode->clock);
pll_rate = pix_rate * factor;
dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
@@ -518,6 +540,7 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
mtk_dpi_config_yc_map(dpi, dpi->yc_map);
mtk_dpi_config_color_format(dpi, dpi->color_format);
mtk_dpi_config_2n_h_fre(dpi);
+ mtk_dpi_config_disable_edge(dpi);
mtk_dpi_sw_reset(dpi, false);
return 0;
@@ -656,6 +679,31 @@ static const struct component_ops mtk_dpi_component_ops = {
.unbind = mtk_dpi_unbind,
};
+static unsigned int mt8173_calculate_factor(int clock)
+{
+ if (clock <= 27000)
+ return 16 * 3;
+ else if (clock <= 74250)
+ return 8 * 3;
+ else if (clock <= 167000)
+ return 4 * 3;
+ else
+ return 2 * 3;
+}
+
+static const struct mtk_dpi_conf mt8173_conf = {
+ .cal_factor = mt8173_calculate_factor,
+ .reg_h_fre_con = 0xe0,
+};
+
+static const struct of_device_id mtk_dpi_of_ids[] = {
+ { .compatible = "mediatek,mt8173-dpi",
+ .data = &mt8173_conf,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mtk_dpi_of_ids);
+
static int mtk_dpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -663,13 +711,18 @@ static int mtk_dpi_probe(struct platform_device *pdev)
struct resource *mem;
struct device_node *bridge_node;
int comp_id;
+ const struct of_device_id *match;
int ret;
+ match = of_match_node(mtk_dpi_of_ids, dev->of_node);
+ if (!match)
+ return -ENODEV;
dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
if (!dpi)
return -ENOMEM;
dpi->dev = dev;
+ dpi->conf = (struct mtk_dpi_conf *)match->data;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dpi->regs = devm_ioremap_resource(dev, mem);
@@ -748,11 +801,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id mtk_dpi_of_ids[] = {
- { .compatible = "mediatek,mt8173-dpi", },
- {}
-};
-
struct platform_driver mtk_dpi_driver = {
.probe = mtk_dpi_probe,
.remove = mtk_dpi_remove,
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
index 4b6ad4751a31..d9db8c4cacd7 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
@@ -223,6 +223,6 @@
#define ESAV_CODE2 (0xFFF << 0)
#define ESAV_CODE3_MSB BIT(16)
-#define DPI_H_FRE_CON 0xE0
+#define EDGE_SEL_EN BIT(5)
#define H_FRE_2N BIT(25)
#endif /* __MTK_DPI_REGS_H */
--
2.12.5
^ permalink raw reply related
* [PATCH 0/7] drm/mediatek: support hdmi output for mt2701 and mt7623
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
Bibby Hsieh (3):
drm/mediatek: implement connection from BLS to DPI0
drm/mediatek: add a error return value when clock driver has been
prepared
drm/mediatek: config component output by device node port
chunhui dai (4):
drm/mediatek: move dpi private data to device
drm/mediatek: fix to get right bridge for dpi encoder
drm/mediatek: add dpi driver for mt2701 and mt7623
drm/mediatek: add hdmi driver for different hardware
drivers/gpu/drm/mediatek/Makefile | 4 +-
drivers/gpu/drm/mediatek/mtk_dpi.c | 125 +++++++---
drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 2 +-
drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 14 +-
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 +-
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 38 ++-
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 4 +-
drivers/gpu/drm/mediatek/mtk_hdmi.c | 88 +++++--
drivers/gpu/drm/mediatek/mtk_hdmi.h | 28 +++
drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 157 +++++++++++++
drivers/gpu/drm/mediatek/mtk_hdmi_regs.h | 1 +
drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 307 +++++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 129 +----------
13 files changed, 716 insertions(+), 183 deletions(-)
create mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
create mode 100644 drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c
--
2.12.5
^ permalink raw reply
* [RESEND PATCH] pinctrl: rockchip: Disable interrupt when changing it's capability
From: Brian Norris @ 2018-05-08 1:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5AF0FF18.1050905@rock-chips.com>
On Tue, May 08, 2018 at 09:36:24AM +0800, Jeffy Chen wrote:
> On 05/08/2018 06:15 AM, Brian Norris wrote:
> > On the other hand...this also implies there may be a race condition
> > there, where we might lose an interrupt if there is an edge between the
> > re-configuration of the polarity in rockchip_irq_demux() and the
> > clearing/handling of the interrupt (handle_edge_irq() ->
> > chip->irq_ack()). If we have an edge between there, then we might ack
> > it, but leave the polarity such that we aren't ready for the next
> > (inverted) edge.
>
> if let me guess, the unexpected irq we saw is the hardware trying to avoid
> losing irq? for example, we set a EDGE_RISING, and the hardware saw the gpio
> is already high, then though it might lost an irq, so fake one for safe?
I won't pretend to know what the IC designers were doing, but I don't
think that would resolve the problem I'm talking about. The sequence is
something like:
1. EDGE_BOTH IRQ occurs (e.g., low to high)
2. reconfigure polarity in rockchip_irq_demux() (polarity=low)
3. continue to handle_edge_irq()
4. another HW edge occurs (e.g., high to low)
5. handle_edge_irq() (from 3) acks (clears) IRQ (before a subsequent
rockchip_irq_demux() gets a chance to run and flip the polarity)
...
Now the polarity is still low, but the next trigger should be a
low-to-high edge.
> i'll try to confirm it with IC guys.
Brian
^ permalink raw reply
* [PATCH v3 1/3] clocksource: timer-ti-dm: remove the early platform driver registration
From: Daniel Lezcano @ 2018-05-08 1:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180504132731.14574-2-brgl@bgdev.pl>
On Fri, May 04, 2018 at 03:27:29PM +0200, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> This driver is no longer used as an early platform driver. Remove the
> registration macro.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
--
<http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* [RESEND PATCH] pinctrl: rockchip: Disable interrupt when changing it's capability
From: JeffyChen @ 2018-05-08 1:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507221511.GA6448@rodete-desktop-imager.corp.google.com>
Hi Brian,
On 05/08/2018 06:15 AM, Brian Norris wrote:
> + Doug
>
> Hi Jeffy,
>
> On Thu, May 03, 2018 at 02:55:53PM +0800, Jeffy Chen wrote:
>> We saw spurious irq when changing irq's trigger type, for example
>> setting gpio-keys's wakeup irq trigger type.
>>
>> And according to the TRM:
>> "Programming the GPIO registers for interrupt capability, edge-sensitive
>> or level-sensitive interrupts, and interrupt polarity should be
>> completed prior to enabling the interrupts on Port A in order to prevent
>> spurious glitches on the interrupt lines to the interrupt controller."
>>
>> Reported-by: Brian Norris <briannorris@google.com>
>> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
>> ---
>>
>> drivers/pinctrl/pinctrl-rockchip.c | 10 ++++++++++
>> 1 file changed, 10 insertions(+)
>>
>> diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
>> index 3924779f55785..7ff45ec8330d1 100644
>> --- a/drivers/pinctrl/pinctrl-rockchip.c
>> +++ b/drivers/pinctrl/pinctrl-rockchip.c
>> @@ -2727,9 +2727,19 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
>> return -EINVAL;
>> }
>>
>> + /**
>
> The typical multiline comment style is to use only 1 asterisk -- 2
> asterisks usually denote something more formal, like kerneldoc.
ok, will fix it.
>
>> + * According to the TRM, we should keep irq disabled during programming
>> + * interrupt capability to prevent spurious glitches on the interrupt
>> + * lines to the interrupt controller.
>> + */
>
> It's also worth noting that this case may come up in
> rockchip_irq_demux() for EDGE_BOTH triggers:
>
> /*
> * Triggering IRQ on both rising and falling edge
> * needs manual intervention.
> */
> if (bank->toggle_edge_mode & BIT(irq)) {
> ...
> polarity = readl_relaxed(bank->reg_base +
> GPIO_INT_POLARITY);
> if (data & BIT(irq))
> polarity &= ~BIT(irq);
> else
> polarity |= BIT(irq);
> writel(polarity,
> bank->reg_base + GPIO_INT_POLARITY);
>
> AIUI, this case is not actually a problem, because this polarity
> reconfiguration happens before we call generic_handle_irq(), so the
> extra spurious interrupt is handled and cleared after this point. But it
> seems like this should be noted somewhere in either the commit message,
> the code comments, or both.
just from my testing, the spurious irq only happen when set EDGE_RISING
to a gpio which is already high level, or set EDGE_FALLING to a gpio
which is already low level.so the demux / EDGE_BOTH seem ok.
but adding comments as your suggested is a good idea, will do that.
>
> On the other hand...this also implies there may be a race condition
> there, where we might lose an interrupt if there is an edge between the
> re-configuration of the polarity in rockchip_irq_demux() and the
> clearing/handling of the interrupt (handle_edge_irq() ->
> chip->irq_ack()). If we have an edge between there, then we might ack
> it, but leave the polarity such that we aren't ready for the next
> (inverted) edge.
if let me guess, the unexpected irq we saw is the hardware trying to
avoid losing irq? for example, we set a EDGE_RISING, and the hardware
saw the gpio is already high, then though it might lost an irq, so fake
one for safe?
i'll try to confirm it with IC guys.
>
> I'm not 100% sure about the above, so it might be good to verify it. But
> I also expect this means there's really no way to 100% reliably
> implement both-edge trigger types on hardware like this that doesn't
> directly implement it. So I'm not sure what we'd do with that knowledge.
>
>> + data = readl(bank->reg_base + GPIO_INTEN);
>> + writel_relaxed(data & ~mask, gc->reg_base + GPIO_INTEN);
>
> Not sure if this is a needless optimization: but couldn't you only
> disable the interrupt (and make the level and polarity changes) only if
> the level or polarity are actually changing? For example, it's possible
> to end up here when changing from EDGE_BOTH to EDGE_RISING, but we might
> not actually program a new value.
right, i noticed that too, will add a patch for that in v2.
>
> Brian
>
>> +
>> writel_relaxed(level, gc->reg_base + GPIO_INTTYPE_LEVEL);
>> writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY);
>>
>> + writel_relaxed(data, gc->reg_base + GPIO_INTEN);
>> +
>> irq_gc_unlock(gc);
>> raw_spin_unlock_irqrestore(&bank->slock, flags);
>> clk_disable(bank->clk);
>> --
>> 2.11.0
>>
>>
>
>
>
^ permalink raw reply
* [PATCH v2 1/2] dt-bindings: add MediaTek XS-PHY binding
From: Chunfeng Yun @ 2018-05-08 1:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507170435.GA14540@rob-hp-laptop>
On Mon, 2018-05-07 at 12:04 -0500, Rob Herring wrote:
> On Sat, May 05, 2018 at 10:15:05AM +0800, Chunfeng Yun wrote:
> > Add a DT binding documentation of XS-PHY for MediaTek SoCs
> > with USB3.1 GEN2 controller
> >
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> > ---
> > .../devicetree/bindings/phy/phy-mtk-xsphy.txt | 110 ++++++++++++++++++++
> > 1 file changed, 110 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/phy/phy-mtk-xsphy.txt
> >
> > diff --git a/Documentation/devicetree/bindings/phy/phy-mtk-xsphy.txt b/Documentation/devicetree/bindings/phy/phy-mtk-xsphy.txt
> > new file mode 100644
> > index 0000000..9a95fab
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/phy/phy-mtk-xsphy.txt
> > @@ -0,0 +1,110 @@
> > +MediaTek XS-PHY binding
> > +--------------------------
> > +
> > +The XS-PHY controller supports physical layer functionality for USB3.1
> > +GEN2 controller on MediaTek SoCs.
> > +
> > +Required properties (controller (parent) node):
> > + - compatible : should be "mediatek,<soc-model>-xsphy", "mediatek,xsphy",
> > + soc-model is the name of SoC, such as mt2712 etc;
> > + when using "mediatek,xsphy" compatible string, you need SoC specific
> > + ones in addition, one of:
> > + - "mediatek,mt3611-xsphy"
>
> What about mt2712 you mention above?
Sorry, forgot to modify it
^ permalink raw reply
* [PATCH v2 2/2] arm64: dts: qcom: msm8998: Add rpm and regulators for MTP
From: Bjorn Andersson @ 2018-05-07 23:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <152573424824.138124.9876892052732688689@swboyd.mtv.corp.google.com>
On Mon 07 May 16:04 PDT 2018, Stephen Boyd wrote:
> Quoting Bjorn Andersson (2018-04-27 22:42:48)
> > diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > index d6665e4f801f..ccbf6347aacb 100644
> > --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > @@ -220,6 +220,16 @@
> > method = "smc";
> > };
> >
> > + rpm_glink: rpm-glink {
> > + compatible = "qcom,glink-rpm";
> > +
> > + interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
> > +
> > + qcom,rpm-msg-ram = <&rpm_msg_ram>;
> > +
> > + mboxes = <&apcs_glb 0>;
>
> Why so many newlines?
>
No particular reason...
> > + };
> > +
> > soc: soc {};
> > };
> >
> > @@ -337,4 +347,77 @@
> > #interrupt-cells = <4>;
> > cell-index = <0>;
> > };
> > +
> > + rpm_msg_ram: memory at 68000 {
>
> unit address doesn't match reg property.
>
Doh...
> > + compatible = "qcom,rpm-msg-ram";
> > + reg = <0x778000 0x7000>;
> > + };
[..]
> > +&rpm_glink {
> > + rpm_requests {
> > + compatible = "qcom,rpm-msm8998";
> > + qcom,glink-channels = "rpm_requests";
> > +
> > + pm8998-regulators {
> > + compatible = "qcom,rpm-pm8998-regulators";
> > +
> > + pm8998_s1: s1 {};
[..]
> > + pm8998_lvs2: lvs2 {};
>
> What's the benefit to having the nodes here instead of in each board?
>
That's how we've done it in the previous boards, but I had a discussion
regarding this with Doug the other day and agree that it might make
sense to just leave them out.
In particular Doug wanted to use labels based on names in the schematics
for his board...
> > + };
> > +
> > + pmi8998-regulators {
> > + compatible = "qcom,rpm-pmi8998-regulators";
> > +
> > + pmi8998_bob: bob {};
> > + };
>
> These may be board specific? So each regulator container would need
> status = "disabled" and then status = "okay" in the board file.
>
Right, we haven't really seen the need for this before, but it seems to
make more sense to move all regulators and their references to the board
file.
Regards,
Bjorn
^ permalink raw reply
* [PATCH v2 1/2] arm64: dts: Add msm8998 SoC and MTP board support
From: Bjorn Andersson @ 2018-05-07 23:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <152573399648.138124.10341359049104453178@swboyd.mtv.corp.google.com>
On Mon 07 May 15:59 PDT 2018, Stephen Boyd wrote:
> Quoting Bjorn Andersson (2018-04-27 22:42:47)
> > diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > new file mode 100644
> > index 000000000000..d6665e4f801f
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > @@ -0,0 +1,340 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. */
> > +
> > +#include <dt-bindings/interrupt-controller/arm-gic.h>
> > +#include <dt-bindings/clock/qcom,gcc-msm8998.h>
> > +
> > +/ {
> > + model = "Qualcomm Technologies, Inc. MSM 8998";
> > +
> > + interrupt-parent = <&intc>;
> > +
> > + qcom,msm-id = <292 0x0>;
>
> No update to dtbtool?
>
This allows me to concatenate the dtb to the Image.gz and boot the
device. From my scripts I see that I tried to use dtbTool before
reverting to this...
[..]
> > + cpu-map {
> > + cluster0 {
> > + core0 {
> > + cpu = <&CPU0>;
> > + };
> > +
> > + core1 {
> > + cpu = <&CPU1>;
> > + };
> > +
> > + core2 {
> > + cpu = <&CPU2>;
> > + };
> > +
> > + core3 {
> > + cpu = <&CPU3>;
> > + };
> > + };
> > +
> > + cluster1 {
> > + core0 {
> > + cpu = <&CPU4>;
> > + };
> > +
> > + core1 {
> > + cpu = <&CPU5>;
> > + };
> > +
> > + core2 {
> > + cpu = <&CPU6>;
> > + };
> > +
> > + core3 {
> > + cpu = <&CPU7>;
> > + };
> > + };
> > + };
>
> I still wonder if this is accurate, but OK.
>
Afaict it matches downstream, not sure if I'm missing something?
[..]
> > + intc: interrupt-controller at 17a00000 {
> > + compatible = "arm,gic-v3";
> > + reg = <0x17a00000 0x10000>, /* GICD */
> > + <0x17b00000 0x100000>; /* GICR * 8 */
> > + #interrupt-cells = <3>;
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + ranges;
> > + interrupt-controller;
> > + #redistributor-regions = <1>;
> > + redistributor-stride = <0x0 0x20000>;
>
> Is this needed? The redistributor stuff can be left out if there's only
> one right?
>
#redistributor-regions is listed as optional if there's more than 1, the
stride is still needed.
Afaict the stride still needs to be specified, as it's different from
the default 64kb.
> > + interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
> > + };
> > +
> > + blsp2_uart1: serial at c1b0000 {
>
> Clk name says uart2 though?
>
That's because it's the wrong clock. Thanks!
> > + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
> > + reg = <0xc1b0000 0x1000>;
> > + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&gcc GCC_BLSP2_UART2_APPS_CLK>,
> > + <&gcc GCC_BLSP2_AHB_CLK>;
> > + clock-names = "core", "iface";
> > + status = "disabled";
> > + };
Regards,
Bjorn
^ permalink raw reply
* [PATCH v2 0/5] crypto: Speck support
From: Eric Biggers @ 2018-05-07 23:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAEX_ruHoVRnBPazLhi6c+ps52yjb_SW=VfwxjiAW8izjvs24uQ@mail.gmail.com>
Hi Samuel,
On Thu, Apr 26, 2018 at 03:05:44AM +0100, Samuel Neves wrote:
> On Wed, Apr 25, 2018 at 8:49 PM, Eric Biggers <ebiggers@google.com> wrote:
> > I agree that my explanation should have been better, and should have considered
> > more crypto algorithms. The main difficulty is that we have extreme performance
> > requirements -- it needs to be 50 MB/s at the very least on even low-end ARM
> > devices like smartwatches. And even with the NEON-accelerated Speck128-XTS
> > performance exceeding that after much optimization, we've been getting a lot of
> > pushback as people want closer to 100 MB/s.
> >
>
> I couldn't find any NEON-capable ARMv7 chip below 800 MHz, so this
> would put the performance upper bound around 15 cycles per byte, with
> the comfortable number being ~7. That's indeed tough, though not
> impossible.
>
> >
> > That's why I also included Speck64-XTS in the patches, since it was
> > straightforward to include, and some devices may really need that last 20-30% of
> > performance for encryption to be feasible at all. (And when the choice is
> > between unencrypted and a 64-bit block cipher, used in a context where the
> > weakest points in the cryptosystem are actually elsewhere such as the user's
> > low-entropy PIN and the flash storage doing wear-leveling, I'd certainly take
> > the 64-bit block cipher.) So far we haven't had to use Speck64 though, and if
> > that continues to be the case I'd be fine with Speck64 being removed, leaving
> > just Speck128.
> >
>
> I would very much prefer that to be the case. As many of us know,
> "it's better than nothing" has been often used to justify other bad
> choices, like RC4, that end up preventing better ones from being
> adopted. At a time where we're trying to get rid of 64-bit ciphers in
> TLS, where data volumes per session are comparatively low, it would be
> unfortunate if the opposite starts happening on encryption at rest.
>
> >
> > Note that in practice, to have any chance at meeting the performance requirement
> > the cipher needed to be NEON accelerated. That made benchmarking really hard
> > and time-consuming, since to definitely know how an algorithm performs it can
> > take upwards of a week to implement a NEON version. It needs to be very well
> > optimized too, to compare the algorithms fairly -- e.g. with Speck I got a 20%
> > performance improvement on some CPUs just by changing the NEON instructions used
> > to implement the 8-bit rotates, an optimization that is not possible with
> > ciphers that don't use rotate amounts that are multiples of 8. (This was an
> > intentional design choice by the Speck designers; they do know what they're
> > doing, actually.)
> >
> > Thus, we had to be pretty aggressive about dropping algorithms from
> > consideration if there were preliminary indications that they wouldn't perform
> > well, or had too little cryptanalysis, or had other issues such as an unclear
> > patent situation. Threefish for example I did test the C implementation at
> > https://github.com/wernerd/Skein3Fish, but on ARM32 it was over 4 times slower
> > than my NEON implementation of Speck128/256-XTS. And I did not see a clear way
> > that it could be improved over 4x with NEON, if at all, so I did not take the
> > long time it would have taken to write an optimized NEON implementation to
> > benchmark it properly. Perhaps that was a mistake. But, time is not unlimited.
> >
>
> In my limited experience with NEON and 64-bit ARX, there's usually a
> ~2x speedup solely from NEON's native 64-bit operations on ARMv7-A.
> The extra speedup from encrypting 2 block in parallel is then
> somewhere between 1x and 2x, depending on various details. Getting
> near 4x might be feasible, but it is indeed time-consuming to get
> there.
>
> >
> > As for the wide-block mode using ChaCha20 and Poly1305, you'd have to ask Paul
> > Crowley to explain it properly, but briefly it's actually a pseudorandom
> > permutation over an arbitrarily-sized message. So with dm-crypt for example, it
> > would operate on a whole 512-byte sector, and if any bit of the 512-byte
> > plaintext is changed, then every bit in the 512-byte ciphertext would change
> > with 50% probability. To make this possible, the construction uses a polynomial
> > evalution in GF(2^130-5) as a universal hash function, similar to the Poly1305
> > mode.
> >
>
> Oh, OK, that sounds like something resembling Naor-Reingold or its
> relatives. That would work, but with 3 or 4 passes I guess it wouldn't
> be very fast.
>
> >
> > Using ChaCha20's underlying 512-bit permutation to build a tweakable block
> > cipher is an interesting idea. But maybe in my crypto-naivety, it is not
> > obvious to me how to do so. Do you have references to any relevant papers?
> > Remember that we strongly prefer a published cipher to a custom one -- even if
> > the core is reused, a mistake may be made in the way it is used. Thus,
> > similarly to Paul's wide-block mode, I'd be concerned that we'd have to
> > self-publish a new construction, then use it with no outside crypto review.
> > *Maybe* it would be straightforward enough to be okay, but to know I'd need to
> > see the details of how it would actually work.
> >
>
> This would be the 'tweakable Even-Mansour' construction and its
> variants. The variant I'm most familiar with would be MEM [1],
> focusing on software friendliness, but there is other provable
> security work in the same vein, including [3, 4, 5]. It's very similar
> to how the XEX mode turns a block cipher into a tweakable block
> cipher.
>
> In [1, 2] we used a 1024-bit permutation out of BLAKE2 instead of
> ChaCha20's, but everything translates easily from one to the other. We
> also included cheap masks for 512-bit permutations, just in case.
>
> [1] https://eprint.iacr.org/2015/999
> [2] https://github.com/MEM-AEAD/mem-aead
> [3] https://eprint.iacr.org/2015/539
> [4] https://eprint.iacr.org/2015/476
> [5] https://competitions.cr.yp.to/round2/minalpherv11.pdf
>
> >
> > But in the end, Speck seemed like the clear choice because it had multiple NEON
> > implementations available already which showed it could be implemented very
> > efficiently in NEON; it has over 70 cryptanalysis papers (far more than most
> > ciphers) yet the security margin is still similar to AES; it has no intellectual
> > property concerns; there is a paper clearly explaining the design decisions; it
> > is naturally resistant to timing attacks; it supports a 128-bit block size, so
> > it can be easily used in XTS mode; it supports the same key sizes as AES; and it
> > has a simple and understandable design with no "magic numbers" besides 8 and 3
> > (compare to an actual backdoored algorithm like Dual_EC_DRGB, which basically
> > had a public key embedded in the algorithm). Also as Paul mentioned he is
> > confident in the construction, and he has published cryptanalysis on Salsa20, so
> > his opinion is probably more significant than mine :-)
> >
> > But I will definitely take a closer look at SPARX and some of the other ciphers
> > you mentioned in case I missed something. I really do appreciate the
> > suggestions, by the way, and in any case we do need to be very well prepared to
> > justify our choices. I just hope that people can understand that we are
> > implementing real-world crypto which must operate under *very* tight performance
> > constraints on ARM processors, and it must be compatible with dm-crypt and
> > fscrypt with no room for ciphertext expansion. Thus, many algorithms which may
> > at first seem reasonable choices had to (unfortunately) be excluded.
> >
>
> I understand it is a tough choice, and it's unfortunate that many of
> the algorithms we have cater mostly to either the
> high-hardware-accelerated-end or the extremely low-end, without a lot
> of good options at the middle-end.
>
First, we're planning a publication which explains our choices in more detail,
so please treat this as some more preliminary notes.
To make sure we've exhausted as many alternatives as possible, I wrote NEON
implementations of all the block ciphers you suggested with the exception of
SKINNY (which looked very hardware-oriented and not efficient in software), as
well as some that others have suggested. (It was tough, but after doing a
couple, it got much easier...) The following shows the decryption performance
I'm getting on an ARMv7 platform. Encryption speeds were usually similar, but
in our use case we care much more about decryption, as that affects the most
critical metrics such as the time to launch applications.
ChaCha8-MEM: 183256 KB/s
ChaCha12-MEM: 134833 KB/s
Chaskey-LTS-XTS: 99097 KB/s
ChaCha20-MEM: 87875 KB/s
Speck64/128-XTS: 85332 KB/s
Speck128/128-XTS: 73404 KB/s
RC5-128/12/256-XTS: 69887 KB/s
Speck128/256-XTS: 69597 KB/s
RC5-64/12/128-XTS: 69267 KB/s
LEA-128-XTS: 67986 KB/s
CHAM128/128-XTS: 52982 KB/s
LEA-256-XTS: 50429 KB/s
Threefish-256: 48349 KB/s
RC6-XTS: 46855 KB/s
RC5-128/20/256-XTS: 44291 KB/s
RC5-64/20/128-XTS: 43924 KB/s
NOEKEON-XTS: 40705 KB/s
Sparx128/128-XTS: 39191 KB/s
XTEA-XTS: 38239 KB/s
AES-128-XTS: 25549 KB/s
AES-256-XTS: 18640 KB/s
Remember that for dm-crypt or fscrypt over flash storage and/or f2fs, a stream
cipher is insecure. Moreover, on these (low-end) devices the status quo is no
encryption, and we need every bit of performance available. Anything below
50 MB/s is definitely unacceptable. But even at that speed we get many
complaints, so in practice we need something faster. That means that the
algorithms close to 50 MB/s, such as Threefish, still aren't fast enough.
ChaCha-MEM (based roughly on your paper: https://eprint.iacr.org/2015/999), has
the best performance, especially if we allow for the 12 or 8-round variants. My
code for it is based roughly on the existing
arch/arm/crypto/chacha20-neon-core.S, but updated to support the inverse
permutation (on 4 blocks at a time, using all 16 NEON registers) and do the
masking required by MEM. However, ChaCha-MEM would be a pretty bleeding-edge
and customized construction, and Paul Crowley and I have concerns about its
security. The problem is that the MEM security proof assumes that the
underlying permutation has no more detectable structural properties than a
randomly selected permutation. However, the ChaCha permutation is known to have
certain symmetries, e.g. if the sixteen 32-bit words are (a, a, a, a, b, b, b,
b, c, c, c, c, d, d, d, d), then they always map to some (e, e, e, e, f, f, f,
f, g, g, g, g, h, h, h, h).
For the MEM mask generation, we can use the "expand 32-byte k" constant to break
the symmetry, like is done in the ChaCha stream cipher. However, that's not
possible for the inner application of the permutation. So, we'd be using the
ChaCha permutation in a manner in which it wasn't intended, and the security of
the ChaCha stream cipher wouldn't directly carry over. Granted, it's not
impossible that it would be secure, but at the present time it doesn't seem like
a good choice to actually field.
Chaskey-LTS is faster than Speck, but unfortunately it's not really a viable
option because it has only a 64-bit security level, due to its use of the
Even-Mansour construction with a 128-bit key. Of course, it would still be
better than nothing, but we prefer a cipher that has a security level in line
with what is accepted for modern crypto.
RC5 with the traditional 12 rounds is about as fast as Speck, but there is a
known differential attack on that number of rounds. So if we choose RC5 we'd
almost certainly have to use the 20-round variant, which is much slower.
That leaves LEA-128-XTS as the only other algorithm that might meet the
performance requirement, as it is only slightly slower than Speck128-XTS. It
may be the most viable alternative, but beyond the slight performance loss it
still has some disadvantages compared to Speck:
- Importantly, the LEA authors forgot to include test vectors, so I'm not yet
100% sure I implemented it correctly. (The Speck authors unfortunately didn't
make the endianness of their test vectors clear in their initial publication,
but at least they actually provided test vectors!)
- LEA has received some cryptanalysis, but not nearly as much as Speck.
- It took some very heavy optimization to get good LEA performance, much more
than I had to do for Speck. My final LEA code has separate code paths for
128-bit and 256-bit keys, and has reordered and preprocessed the round keys,
and reordered the operations. As a result, it's harder to see how it maps to
the original paper. In contrast, my Speck code is more straightforward and
maintainable.
- LEA-256 (256-bit key) is much slower than LEA-128 (128-bit key), as it has
33% more rounds. LEA-256 would not be fast enough, so we would have to use
LEA-128. In contrast, with Speck we can use Speck128/256 (256-bit key).
We're willing to accept a 128-bit security level, but 256-bit is preferable.
(I think the Speck designers took a more informed approach to setting
appropriate security margins for a lightweight cipher; it seems that other
designers often choose too few or too many rounds, especially as the key
length is varied.)
- LEA encryption is also a bit slower than decryption, while with Speck
encryption and decryption are almost exactly the same speed.
Note that like Speck, LEA doesn't appear to be approved by a standards
organization either; it's just specified in a research paper.
Thus, from a technical perspective, and given the current state of the art in
lightweight cryptography, currently Speck128-XTS seems to be the best choice for
the problem domain. It's unfortunate that there are so few good options and
that the field is so politicized, but it is what it is.
Still, we don't want to abandon HPolyC (Paul's new ChaCha and Poly1305-based
wide-block mode), and eventually we hope to offer it as an option as well. But
it's not yet published, and it's a more complex algorithm that is harder to
implement so I haven't yet had a chance to implement and benchmark it. And we
don't want to continue to leave users unprotected while we spend a long time
coming up with the perfect algorithm, or for hardware AES support to arrive to
all low-end CPUs when it's unclear if/when that will happen.
Again, we're planning a publication which will explain all this in more detail.
Thanks!
Eric
^ permalink raw reply
* [PATCH v2 2/2] arm64: dts: qcom: msm8998: Add rpm and regulators for MTP
From: Stephen Boyd @ 2018-05-07 23:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180428054248.22387-2-bjorn.andersson@linaro.org>
Quoting Bjorn Andersson (2018-04-27 22:42:48)
> diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> index d6665e4f801f..ccbf6347aacb 100644
> --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> @@ -220,6 +220,16 @@
> method = "smc";
> };
>
> + rpm_glink: rpm-glink {
> + compatible = "qcom,glink-rpm";
> +
> + interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
> +
> + qcom,rpm-msg-ram = <&rpm_msg_ram>;
> +
> + mboxes = <&apcs_glb 0>;
Why so many newlines?
> + };
> +
> soc: soc {};
> };
>
> @@ -337,4 +347,77 @@
> #interrupt-cells = <4>;
> cell-index = <0>;
> };
> +
> + rpm_msg_ram: memory at 68000 {
unit address doesn't match reg property.
> + compatible = "qcom,rpm-msg-ram";
> + reg = <0x778000 0x7000>;
> + };
> +
> + apcs_glb: mailbox at 9820000 {
unit address doesn't match reg property.
> + compatible = "qcom,msm8998-apcs-hmss-global";
> + reg = <0x17911000 0x1000>;
> +
> + #mbox-cells = <1>;
> + };
> +};
> +
> +&rpm_glink {
> + rpm_requests {
> + compatible = "qcom,rpm-msm8998";
> + qcom,glink-channels = "rpm_requests";
> +
> + pm8998-regulators {
> + compatible = "qcom,rpm-pm8998-regulators";
> +
> + pm8998_s1: s1 {};
> + pm8998_s2: s2 {};
> + pm8998_s3: s3 {};
> + pm8998_s4: s4 {};
> + pm8998_s5: s5 {};
> + pm8998_s6: s6 {};
> + pm8998_s7: s7 {};
> + pm8998_s8: s8 {};
> + pm8998_s9: s9 {};
> + pm8998_s10: s10 {};
> + pm8998_s11: s11 {};
> + pm8998_s12: s12 {};
> + pm8998_s13: s13 {};
> + pm8998_l1: l1 {};
> + pm8998_l2: l2 {};
> + pm8998_l3: l3 {};
> + pm8998_l4: l4 {};
> + pm8998_l5: l5 {};
> + pm8998_l6: l6 {};
> + pm8998_l7: l7 {};
> + pm8998_l8: l8 {};
> + pm8998_l9: l9 {};
> + pm8998_l10: l10 {};
> + pm8998_l11: l11 {};
> + pm8998_l12: l12 {};
> + pm8998_l13: l13 {};
> + pm8998_l14: l14 {};
> + pm8998_l15: l15 {};
> + pm8998_l16: l16 {};
> + pm8998_l17: l17 {};
> + pm8998_l18: l18 {};
> + pm8998_l19: l19 {};
> + pm8998_l20: l20 {};
> + pm8998_l21: l21 {};
> + pm8998_l22: l22 {};
> + pm8998_l23: l23 {};
> + pm8998_l24: l24 {};
> + pm8998_l25: l25 {};
> + pm8998_l26: l26 {};
> + pm8998_l27: l27 {};
> + pm8998_l28: l28 {};
> + pm8998_lvs1: lvs1 {};
> + pm8998_lvs2: lvs2 {};
What's the benefit to having the nodes here instead of in each board?
> + };
> +
> + pmi8998-regulators {
> + compatible = "qcom,rpm-pmi8998-regulators";
> +
> + pmi8998_bob: bob {};
> + };
These may be board specific? So each regulator container would need
status = "disabled" and then status = "okay" in the board file.
^ permalink raw reply
* [PATCH v2 1/2] arm64: dts: Add msm8998 SoC and MTP board support
From: Stephen Boyd @ 2018-05-07 22:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180428054248.22387-1-bjorn.andersson@linaro.org>
Quoting Bjorn Andersson (2018-04-27 22:42:47)
> diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> new file mode 100644
> index 000000000000..d6665e4f801f
> --- /dev/null
> +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> @@ -0,0 +1,340 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. */
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/clock/qcom,gcc-msm8998.h>
> +
> +/ {
> + model = "Qualcomm Technologies, Inc. MSM 8998";
> +
> + interrupt-parent = <&intc>;
> +
> + qcom,msm-id = <292 0x0>;
No update to dtbtool?
> +
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + chosen { };
> +
> + memory {
> + device_type = "memory";
> + /* We expect the bootloader to fill in the reg */
> + reg = <0 0 0 0>;
> + };
> +
> + cpus {
> + #address-cells = <2>;
> + #size-cells = <0>;
> +
> + CPU0: cpu at 0 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x0>;
> + enable-method = "psci";
> + efficiency = <1024>;
> + next-level-cache = <&L2_0>;
> + L2_0: l2-cache {
> + compatible = "arm,arch-cache";
> + cache-level = <2>;
> + };
> + L1_I_0: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_0: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU1: cpu at 1 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x1>;
> + enable-method = "psci";
> + efficiency = <1024>;
> + next-level-cache = <&L2_0>;
> + L1_I_1: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_1: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU2: cpu at 2 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x2>;
> + enable-method = "psci";
> + efficiency = <1024>;
> + next-level-cache = <&L2_0>;
> + L1_I_2: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_2: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU3: cpu at 3 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x3>;
> + enable-method = "psci";
> + efficiency = <1024>;
> + next-level-cache = <&L2_0>;
> + L1_I_3: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_3: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU4: cpu at 100 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x100>;
> + enable-method = "psci";
> + efficiency = <1536>;
> + next-level-cache = <&L2_1>;
> + L2_1: l2-cache {
> + compatible = "arm,arch-cache";
> + cache-level = <2>;
> + };
> + L1_I_100: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_100: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU5: cpu at 101 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x101>;
> + enable-method = "psci";
> + efficiency = <1536>;
> + next-level-cache = <&L2_1>;
> + L1_I_101: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_101: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU6: cpu at 102 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x102>;
> + enable-method = "psci";
> + efficiency = <1536>;
> + next-level-cache = <&L2_1>;
> + L1_I_102: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_102: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU7: cpu at 103 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x103>;
> + enable-method = "psci";
> + efficiency = <1536>;
> + next-level-cache = <&L2_1>;
> + L1_I_103: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_103: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + cpu-map {
> + cluster0 {
> + core0 {
> + cpu = <&CPU0>;
> + };
> +
> + core1 {
> + cpu = <&CPU1>;
> + };
> +
> + core2 {
> + cpu = <&CPU2>;
> + };
> +
> + core3 {
> + cpu = <&CPU3>;
> + };
> + };
> +
> + cluster1 {
> + core0 {
> + cpu = <&CPU4>;
> + };
> +
> + core1 {
> + cpu = <&CPU5>;
> + };
> +
> + core2 {
> + cpu = <&CPU6>;
> + };
> +
> + core3 {
> + cpu = <&CPU7>;
> + };
> + };
> + };
I still wonder if this is accurate, but OK.
> + };
> +
> + timer {
> + compatible = "arm,armv8-timer";
> + interrupts = <GIC_PPI 1 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_PPI 2 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_PPI 3 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_PPI 0 IRQ_TYPE_LEVEL_LOW>;
> + };
> +
> + clocks {
> + xo_board {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <19200000>;
> + };
> +
> + sleep_clk {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <32764>;
> + };
> + };
> +
> + psci {
> + compatible = "arm,psci-1.0";
> + method = "smc";
> + };
> +
> + soc: soc {};
> +};
> +
> +&soc {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0 0 0 0xffffffff>;
> + compatible = "simple-bus";
> +
> + intc: interrupt-controller at 17a00000 {
> + compatible = "arm,gic-v3";
> + reg = <0x17a00000 0x10000>, /* GICD */
> + <0x17b00000 0x100000>; /* GICR * 8 */
> + #interrupt-cells = <3>;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges;
> + interrupt-controller;
> + #redistributor-regions = <1>;
> + redistributor-stride = <0x0 0x20000>;
Is this needed? The redistributor stuff can be left out if there's only
one right?
> + interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
> + };
> +
> + blsp2_uart1: serial at c1b0000 {
Clk name says uart2 though?
> + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
> + reg = <0xc1b0000 0x1000>;
> + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&gcc GCC_BLSP2_UART2_APPS_CLK>,
> + <&gcc GCC_BLSP2_AHB_CLK>;
> + clock-names = "core", "iface";
> + status = "disabled";
> + };
> +
^ permalink raw reply
* [PATCH v2 24/27] coresight: tmc-etr: Relax collection of trace from sysfs mode
From: Mathieu Poirier @ 2018-05-07 22:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525165857-11096-25-git-send-email-suzuki.poulose@arm.com>
On Tue, May 01, 2018 at 10:10:54AM +0100, Suzuki K Poulose wrote:
> Since the ETR now uses mode specific buffers, we can reliably
> provide the trace data captured in sysfs mode, even when the ETR
> is operating in PERF mode.
>
> Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-tmc-etr.c | 14 ++++++--------
> 1 file changed, 6 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index a35a12f..7551272 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -1439,19 +1439,17 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
> goto out;
> }
>
> - /* Don't interfere if operated from Perf */
> - if (drvdata->mode == CS_MODE_PERF) {
> - ret = -EINVAL;
> - goto out;
> - }
> -
> - /* If sysfs_buf is NULL the trace data has been read already */
> + /*
> + * We can safely allow reads even if the ETR is operating in PERF mode,
> + * since the sysfs session is captured in mode specific data.
> + * If drvdata::sysfs_data is NULL the trace data has been read already.
> + */
> if (!drvdata->sysfs_buf) {
> ret = -EINVAL;
> goto out;
> }
>
> - /* Disable the TMC if we are trying to read from a running session */
> + /* Disable the TMC if we are trying to read from a running session. */
Move that to the previous patch.
> if (drvdata->mode == CS_MODE_SYSFS)
> tmc_etr_disable_hw(drvdata);
>
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH v4 3/9] dt-bindings: input: touchscreen: add pressure threshold touchscreen property
From: Dmitry Torokhov @ 2018-05-07 22:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525084335-11276-4-git-send-email-eugen.hristev@microchip.com>
On Mon, Apr 30, 2018 at 01:32:09PM +0300, Eugen Hristev wrote:
> Add a common touchscreen optional property that will specify
> the minimum pressure applied to the screen that is needed
> such that the driver will report the touch event.
>
> Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
> index 537643e..c84047a 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
> +++ b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
> @@ -7,6 +7,9 @@ Optional properties for Touchscreens:
> (in pixels)
> - touchscreen-max-pressure : maximum reported pressure (arbitrary range
> dependent on the controller)
> + - touchscreen-threshold-pressure: minimum pressure on the touchscreen to be
> + achieved in order for the touchscreen
> + driver to report a touch event.
Why do we move from the pattern and call it trheshold and not
touchscreen-min-pressure?
> - touchscreen-fuzz-x : horizontal noise value of the absolute input
> device (in pixels)
> - touchscreen-fuzz-y : vertical noise value of the absolute input
> --
> 2.7.4
>
Thanks.
--
Dmitry
^ permalink raw reply
* [RFC PATCH] driver core: make deferring probe forever optional
From: Bjorn Andersson @ 2018-05-07 22:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAL_Jsq+PRUR5rCeV820XZuQmQH3gD-X=6a5fNuF-9qVbq5dqFg@mail.gmail.com>
On Mon 07 May 12:55 PDT 2018, Rob Herring wrote:
> On Mon, May 7, 2018 at 1:31 PM, Bjorn Andersson
> <bjorn.andersson@linaro.org> wrote:
> > On Tue 01 May 14:31 PDT 2018, Rob Herring wrote:
> >
> >> Deferred probe will currently wait forever on dependent devices to probe,
> >> but sometimes a driver will never exist. It's also not always critical for
> >> a driver to exist. Platforms can rely on default configuration from the
> >> bootloader or reset defaults for things such as pinctrl and power domains.
> >
> > But how do you know if this is the case?
>
> Because the platform worked before adding the dependency in the dts.
>
I'm worried about how to write dts files and drivers to support all
permutation of forward and backward dependencies. And you most
definitely have the same case with bootloader-enabled clocks,
regulators and interconnects.
> >> This is often the case with initial platform support until various drivers
> >> get enabled.
> >
> > Can you please name platform that has enough support for Alexander to
> > care about backwards and forwards compatibility but lacks a pinctrl
> > driver.
>
> Alex will have to answer that. I do agree pinctrl drivers shouldn't be
> that hard because it is all just translating a bunch of pin data into
> one-time (mostly) register writes, so it shouldn't take that long to
> implement support. OTOH, maybe a pinctrl driver is low priority
> because nothing needs it yet. Either a given board works with the
> defaults and only some new board needs to change things or you don't
> need pinctrl until low power modes are implemented. However, power
> domains have the same problem and it can take years for those to get
> proper support.
>
> Alex proposed declaring dts files stable and then enforcing
> compatibility after that point. If anyone believes that will work,
> then please send a patch marking all the platforms in the kernel tree
> that are stable.
>
That might be a reasonable idea, but at least in our corner the current
decision that devicetree should be backwards compatible does make it
quite cumbersome to break this assumption - and in the cases we have had
to do it it's really been necessary.
> >> There's at least 2 scenarios where deferred probe can render
> >> a platform broken. Both involve using a DT which has more devices and
> >> dependencies than the kernel supports. The 1st case is a driver may be
> >> disabled in the kernel config.
> >
> > I agree that there is a chance that you _might_ get some parts of the
> > system working by relying on the boot loader configuration, but
> > misconfiguration issues applies to any other fundamental providers, such
> > as clocks, regulators, power domains and gpios as well.
>
> If it is only a chance, then perhaps we shouldn't allow things
> upstream without proper drivers for all these things. That will only
> give users the wrong impression.
>
It's not as much the drivers that's the problem here as it is the
composition of the drivers. For this particular case it would be
convenient not to ship the partial dtb, or at least not ship it with the
promise that it's stable.
> >> The 2nd case is the kernel version may
> >> simply not have the dependent driver. This can happen if using a newer DT
> >> (provided by firmware perhaps) with a stable kernel version.
> >>
> >
> > As above, this is in no way limited to pinctrl drivers.
>
> Yes, I wasn't trying to imply that with this patch. I was just
> starting with 1 example. IOMMUs (which essentially is already doing
> what this patch does) and power domains are the main other 2.
qcom,iommu-v1 is bool, but depends on e.g. CONFIG_MSM_GCC_8916 which is
tristate. So you would need to s/tristate/bool/ everything in
drivers/clk/qcom/Kconfig as well. Not to mention that there are
interconnects and power domains actually involved here as well...
> Clocks is an obvious one too, but from the discussion I referenced
> that problem is a bit different as platforms change from dummy
> fixed-clocks to a real clock controller driver. That will need a
> different solution.
So how are you going to deal with the case when a vendor decides to ship
their firmware package with all clocks enabled and only fixed clocks
described in DT and as they upstream a clock driver and patch their
firmware to do the right thing?
(Or the much less extreme case where this happens for a single clock,
regulator, pinctrl, interconnect, etc to fix some bug/power management
behavior)
And is this really a problem that does not exists in the ACPI world?
>
> >> Unfortunately, this change breaks with modules as we have no way of
> >> knowing when modules are done loading. One possibility is to make this
> >> opt in or out based on compatible strings rather than at a subsystem level.
> >> Ideally this information could be extracted automatically somehow. OTOH,
> >> maybe the lists are pretty small. There's only a handful of subsystems
> >> that can be optional, and then only so many drivers in those that can be
> >> modules (at least for pinctrl, many drivers are built-in only).
> >>
> >
> > On the Qualcomm platform most drivers are tristate and on most platforms
> > there are size restrictions in the proprietary boot loader preventing us
> > from boot the kernel after switching all these frameworks from tristate
> > to bool (which feels like a more appropriate solution than your hack).
>
> BTW, QCom platforms are almost the only ones with pinctrl drivers as
> modules. They are also happen to be PIA to configure correctly for a
> board.
>
There are a few pinctrl drivers for chips sitting on i2c busses, as such
changing this requirement would trickle down to a number of possible i2c
masters as well.
Sorry to hear that you find it so difficult to configure the pinctrl,
it's (almost) entirely using the common pinctrl bindings. Perhaps we
need to add some documentation of the hardware in the binding?
> However, I would like a solution that works with modules. It would be
> nice to know when userspace finished processing all the coldplug
> uevents. That would be sufficient to support modules. I researched
> that a bit and it doesn't seem the kernel can tell when that has
> happened.
>
It's not that far from the issue I have in remoteproc, where I would
like to boot a DSP as soon as the firmware is available - which might be
probed at any time after boot.
[..]
> >> I tested this on a RPi3 B with the pinctrl driver forced off. With this
> >> change, the MMC/SD and UART drivers can function without the pinctrl
> >> driver.
> >>
> >
> > Cool, so what about graphics, audio, networking, usb and all the other
> > things that people actually expect when they _use_ a distro?
>
> I often care about none of those things. When I do, I'd rather boot to
> a working console with those broken than have to debug why the kernel
> panicked.
>
But that's developer-you speaking, developer-me totally agree.
But when I take the role of being a user of a distro I most definitely
do expect functionality beyond the basics used by the boot loader (UART
and dependencies of the primary storage device).
My argument is simply that in neither of these cases this patch is
helpful.
[..]
> >> +int driver_deferred_probe_optional(void)
> >> +{
> >> + if (initcalls_done)
> >> + return -ENODEV;
> >
> > You forgot the humongous printout here that tells the users that we do
> > not want any bug reports related hardware not working as expected after
> > this point.
>
> I assume you were joking, but I would happily add a WARN here.
About the print yes, but I most definitely do not want to debug issues
related to this!
The crazy issues you get from having electrical properties slightly off
(e.g. drive-strength of the SD-card pins) or the fact that any driver
using pinmuxing will depend on the modprobe ordering.
> Spewing new warnings while still booting is a better UX than just
> panicking. Ideally, it would be once per missing dependency.
>
Having a convenient way of listing all unmatched devices or devices
sitting in probe deferral would be quite convenient, as a development
tool. I know this hassle was the starting point of some of Frank's
tools.
Regards,
Bjorn
^ permalink raw reply
* coresight: documentation: update sysfs section
From: Kim Phillips @ 2018-05-07 22:29 UTC (permalink / raw)
To: linux-arm-kernel
- Align and show updated ls devices output from the TC2, based on
current driver
- Provide an example from an ETMv4 based system (Juno)
- Reflect changes to the way the RAM write pointer is accessed since
it got changed in commit 7d83d17795ef ("coresight: tmc: adding sysFS
management entries").
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Kim Phillips <kim.phillips@arm.com>
---
Documentation/trace/coresight.txt | 40 ++++++++++++++++++-------------
1 file changed, 24 insertions(+), 16 deletions(-)
diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt
index 6f0120c3a4f1..d23d6354b372 100644
--- a/Documentation/trace/coresight.txt
+++ b/Documentation/trace/coresight.txt
@@ -144,10 +144,21 @@ If everything goes well during the registration process the new devices will
show up under /sys/bus/coresight/devices, as showns here for a TC2 platform:
root:~# ls /sys/bus/coresight/devices/
-replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm
-20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm
+20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm replicator
+20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm
root:~#
+and here for a Juno platform:
+
+root at juno:~# ls /sys/bus/coresight/devices/
+20010000.etf 20120000.replicator 22040000.etm 230c0000.funnel
+20030000.tpiu 20130000.funnel 220c0000.funnel 23140000.etm
+20040000.funnel 20140000.etf 22140000.etm 23240000.etm
+20070000.etr 20150000.funnel 23040000.etm 23340000.etm
+root at juno:~#
+
+Note the Juno uses an Embedded Trace Router (ETR) instead of an ETB.
+
The functions take a "struct coresight_device", which looks like this:
struct coresight_desc {
@@ -193,16 +204,16 @@ the information carried in "THIS_MODULE".
How to use the tracer modules
-----------------------------
-Before trace collection can start, a coresight sink needs to be identify.
+Before trace collection can start, a coresight sink needs to be identified.
There is no limit on the amount of sinks (nor sources) that can be enabled at
any given moment. As a generic operation, all device pertaining to the sink
class will have an "active" entry in sysfs:
root:/sys/bus/coresight/devices# ls
-replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm
-20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm
+20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm replicator
+20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm
root:/sys/bus/coresight/devices# ls 20010000.etb
-enable_sink status trigger_cntr
+enable_sink mgmt power subsystem trigger_cntr uevent
root:/sys/bus/coresight/devices# echo 1 > 20010000.etb/enable_sink
root:/sys/bus/coresight/devices# cat 20010000.etb/enable_sink
1
@@ -216,16 +227,13 @@ trigger a trace capture:
root:/sys/bus/coresight/devices# echo 1 > 2201c000.ptm/enable_source
root:/sys/bus/coresight/devices# cat 2201c000.ptm/enable_source
1
-root:/sys/bus/coresight/devices# cat 20010000.etb/status
-Depth: 0x2000
-Status: 0x1
-RAM read ptr: 0x0
-RAM wrt ptr: 0x19d3 <----- The write pointer is moving
-Trigger cnt: 0x0
-Control: 0x1
-Flush status: 0x0
-Flush ctrl: 0x2001
-root:/sys/bus/coresight/devices#
+
+Observe the write pointer moving:
+
+root:/sys/bus/coresight/devices# cat 20010000.etb/mgmt/rwp
+0x1a8
+root:/sys/bus/coresight/devices# cat 20010000.etb/mgmt/rwp
+0x19a6
Trace collection is stopped the same way:
--
2.17.0
^ permalink raw reply related
* [PATCH v2 21/27] coresight: Convert driver messages to dev_dbg
From: Mathieu Poirier @ 2018-05-07 22:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525165857-11096-22-git-send-email-suzuki.poulose@arm.com>
On Tue, May 01, 2018 at 10:10:51AM +0100, Suzuki K Poulose wrote:
> Convert component enable/disable messages from dev_info to dev_dbg.
> This is required to prevent LOCKDEP splats when operating in perf
> mode where we could be called with locks held to enable a coresight
> path. If someone wants to really see the messages, they can always
> enable it at runtime via dynamic_debug.
I'm also in favor of moving to dev_dbg() - the messages they produce are useless
unless serious debugging of the CS framework is happening. But as Robin Murphy
pointed out it would be great to fix the problem for real rather than masking
it.
I understand this kind of work would be outside the scope of this set. As such
I'd take this patch but the log message would need to be modified to avoid
talking about LOCKDEP splats, only to make sure nobody thinks the problem has
been fixed.
That being said I work extensively with the CS framework every day (with option
CONFIG_LOCKED_SUPPORT=y) and haven't seen any splats. Perhaps you have a
recipe to reproduce the problem?
>
> Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-dynamic-replicator.c | 4 ++--
> drivers/hwtracing/coresight/coresight-etb10.c | 6 +++---
> drivers/hwtracing/coresight/coresight-etm3x.c | 4 ++--
> drivers/hwtracing/coresight/coresight-etm4x.c | 4 ++--
> drivers/hwtracing/coresight/coresight-funnel.c | 4 ++--
> drivers/hwtracing/coresight/coresight-replicator.c | 4 ++--
> drivers/hwtracing/coresight/coresight-stm.c | 4 ++--
> drivers/hwtracing/coresight/coresight-tmc-etf.c | 8 ++++----
> drivers/hwtracing/coresight/coresight-tmc-etr.c | 4 ++--
> drivers/hwtracing/coresight/coresight-tmc.c | 4 ++--
> drivers/hwtracing/coresight/coresight-tpiu.c | 4 ++--
> 11 files changed, 25 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c
> index 043da86..c41d95c 100644
> --- a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c
> +++ b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c
> @@ -64,7 +64,7 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
>
> CS_LOCK(drvdata->base);
>
> - dev_info(drvdata->dev, "REPLICATOR enabled\n");
> + dev_dbg(drvdata->dev, "REPLICATOR enabled\n");
> return 0;
> }
>
> @@ -83,7 +83,7 @@ static void replicator_disable(struct coresight_device *csdev, int inport,
>
> CS_LOCK(drvdata->base);
>
> - dev_info(drvdata->dev, "REPLICATOR disabled\n");
> + dev_dbg(drvdata->dev, "REPLICATOR disabled\n");
> }
>
> static const struct coresight_ops_link replicator_link_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
> index 74232e6..d9c2f87 100644
> --- a/drivers/hwtracing/coresight/coresight-etb10.c
> +++ b/drivers/hwtracing/coresight/coresight-etb10.c
> @@ -163,7 +163,7 @@ static int etb_enable(struct coresight_device *csdev, u32 mode)
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> out:
> - dev_info(drvdata->dev, "ETB enabled\n");
> + dev_dbg(drvdata->dev, "ETB enabled\n");
> return 0;
> }
>
> @@ -269,7 +269,7 @@ static void etb_disable(struct coresight_device *csdev)
>
> local_set(&drvdata->mode, CS_MODE_DISABLED);
>
> - dev_info(drvdata->dev, "ETB disabled\n");
> + dev_dbg(drvdata->dev, "ETB disabled\n");
> }
>
> static void *etb_alloc_buffer(struct coresight_device *csdev, int cpu,
> @@ -512,7 +512,7 @@ static void etb_dump(struct etb_drvdata *drvdata)
> }
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> - dev_info(drvdata->dev, "ETB dumped\n");
> + dev_dbg(drvdata->dev, "ETB dumped\n");
> }
>
> static int etb_open(struct inode *inode, struct file *file)
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
> index 39f42fd..9d4a663 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x.c
> @@ -510,7 +510,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
> drvdata->sticky_enable = true;
> spin_unlock(&drvdata->spinlock);
>
> - dev_info(drvdata->dev, "ETM tracing enabled\n");
> + dev_dbg(drvdata->dev, "ETM tracing enabled\n");
> return 0;
>
> err:
> @@ -613,7 +613,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
> spin_unlock(&drvdata->spinlock);
> cpus_read_unlock();
>
> - dev_info(drvdata->dev, "ETM tracing disabled\n");
> + dev_dbg(drvdata->dev, "ETM tracing disabled\n");
> }
>
> static void etm_disable(struct coresight_device *csdev,
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
> index e84d80b..c9c73c2 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.c
> @@ -274,7 +274,7 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
> drvdata->sticky_enable = true;
> spin_unlock(&drvdata->spinlock);
>
> - dev_info(drvdata->dev, "ETM tracing enabled\n");
> + dev_dbg(drvdata->dev, "ETM tracing enabled\n");
> return 0;
>
> err:
> @@ -387,7 +387,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
> spin_unlock(&drvdata->spinlock);
> cpus_read_unlock();
>
> - dev_info(drvdata->dev, "ETM tracing disabled\n");
> + dev_dbg(drvdata->dev, "ETM tracing disabled\n");
> }
>
> static void etm4_disable(struct coresight_device *csdev,
> diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
> index 9f8ac0be..18b5361 100644
> --- a/drivers/hwtracing/coresight/coresight-funnel.c
> +++ b/drivers/hwtracing/coresight/coresight-funnel.c
> @@ -72,7 +72,7 @@ static int funnel_enable(struct coresight_device *csdev, int inport,
>
> funnel_enable_hw(drvdata, inport);
>
> - dev_info(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
> + dev_dbg(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
> return 0;
> }
>
> @@ -96,7 +96,7 @@ static void funnel_disable(struct coresight_device *csdev, int inport,
>
> funnel_disable_hw(drvdata, inport);
>
> - dev_info(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
> + dev_dbg(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
> }
>
> static const struct coresight_ops_link funnel_link_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
> index 3756e71..4f77812 100644
> --- a/drivers/hwtracing/coresight/coresight-replicator.c
> +++ b/drivers/hwtracing/coresight/coresight-replicator.c
> @@ -42,7 +42,7 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
> {
> struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>
> - dev_info(drvdata->dev, "REPLICATOR enabled\n");
> + dev_dbg(drvdata->dev, "REPLICATOR enabled\n");
> return 0;
> }
>
> @@ -51,7 +51,7 @@ static void replicator_disable(struct coresight_device *csdev, int inport,
> {
> struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>
> - dev_info(drvdata->dev, "REPLICATOR disabled\n");
> + dev_dbg(drvdata->dev, "REPLICATOR disabled\n");
> }
>
> static const struct coresight_ops_link replicator_link_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
> index 15e7ef38..4c88d99 100644
> --- a/drivers/hwtracing/coresight/coresight-stm.c
> +++ b/drivers/hwtracing/coresight/coresight-stm.c
> @@ -218,7 +218,7 @@ static int stm_enable(struct coresight_device *csdev,
> stm_enable_hw(drvdata);
> spin_unlock(&drvdata->spinlock);
>
> - dev_info(drvdata->dev, "STM tracing enabled\n");
> + dev_dbg(drvdata->dev, "STM tracing enabled\n");
> return 0;
> }
>
> @@ -281,7 +281,7 @@ static void stm_disable(struct coresight_device *csdev,
> pm_runtime_put(drvdata->dev);
>
> local_set(&drvdata->mode, CS_MODE_DISABLED);
> - dev_info(drvdata->dev, "STM tracing disabled\n");
> + dev_dbg(drvdata->dev, "STM tracing disabled\n");
> }
> }
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 1dd44fd..0a32734 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -244,7 +244,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
> if (ret)
> return ret;
>
> - dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n");
> + dev_dbg(drvdata->dev, "TMC-ETB/ETF enabled\n");
> return 0;
> }
>
> @@ -267,7 +267,7 @@ static void tmc_disable_etf_sink(struct coresight_device *csdev)
>
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> - dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n");
> + dev_dbg(drvdata->dev, "TMC-ETB/ETF disabled\n");
> }
>
> static int tmc_enable_etf_link(struct coresight_device *csdev,
> @@ -286,7 +286,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
> drvdata->mode = CS_MODE_SYSFS;
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> - dev_info(drvdata->dev, "TMC-ETF enabled\n");
> + dev_dbg(drvdata->dev, "TMC-ETF enabled\n");
> return 0;
> }
>
> @@ -306,7 +306,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
> drvdata->mode = CS_MODE_DISABLED;
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> - dev_info(drvdata->dev, "TMC-ETF disabled\n");
> + dev_dbg(drvdata->dev, "TMC-ETF disabled\n");
> }
>
> static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int cpu,
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 41dde0a..1ef0f62 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -1350,7 +1350,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
> tmc_etr_free_sysfs_buf(free_buf);
>
> if (!ret)
> - dev_info(drvdata->dev, "TMC-ETR enabled\n");
> + dev_dbg(drvdata->dev, "TMC-ETR enabled\n");
>
> return ret;
> }
> @@ -1393,7 +1393,7 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)
>
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> - dev_info(drvdata->dev, "TMC-ETR disabled\n");
> + dev_dbg(drvdata->dev, "TMC-ETR disabled\n");
> }
>
> static const struct coresight_ops_sink tmc_etr_sink_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
> index 4d41b4b..7adcde3 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc.c
> @@ -92,7 +92,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
> }
>
> if (!ret)
> - dev_info(drvdata->dev, "TMC read start\n");
> + dev_dbg(drvdata->dev, "TMC read start\n");
>
> return ret;
> }
> @@ -114,7 +114,7 @@ static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
> }
>
> if (!ret)
> - dev_info(drvdata->dev, "TMC read end\n");
> + dev_dbg(drvdata->dev, "TMC read end\n");
>
> return ret;
> }
> diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
> index 805f7c2..c7f0827 100644
> --- a/drivers/hwtracing/coresight/coresight-tpiu.c
> +++ b/drivers/hwtracing/coresight/coresight-tpiu.c
> @@ -80,7 +80,7 @@ static int tpiu_enable(struct coresight_device *csdev, u32 mode)
>
> tpiu_enable_hw(drvdata);
>
> - dev_info(drvdata->dev, "TPIU enabled\n");
> + dev_dbg(drvdata->dev, "TPIU enabled\n");
> return 0;
> }
>
> @@ -106,7 +106,7 @@ static void tpiu_disable(struct coresight_device *csdev)
>
> tpiu_disable_hw(drvdata);
>
> - dev_info(drvdata->dev, "TPIU disabled\n");
> + dev_dbg(drvdata->dev, "TPIU disabled\n");
> }
>
> static const struct coresight_ops_sink tpiu_sink_ops = {
> --
> 2.7.4
>
^ permalink raw reply
* [RESEND PATCH] pinctrl: rockchip: Disable interrupt when changing it's capability
From: Brian Norris @ 2018-05-07 22:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503065553.7762-1-jeffy.chen@rock-chips.com>
+ Doug
Hi Jeffy,
On Thu, May 03, 2018 at 02:55:53PM +0800, Jeffy Chen wrote:
> We saw spurious irq when changing irq's trigger type, for example
> setting gpio-keys's wakeup irq trigger type.
>
> And according to the TRM:
> "Programming the GPIO registers for interrupt capability, edge-sensitive
> or level-sensitive interrupts, and interrupt polarity should be
> completed prior to enabling the interrupts on Port A in order to prevent
> spurious glitches on the interrupt lines to the interrupt controller."
>
> Reported-by: Brian Norris <briannorris@google.com>
> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
> ---
>
> drivers/pinctrl/pinctrl-rockchip.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
> index 3924779f55785..7ff45ec8330d1 100644
> --- a/drivers/pinctrl/pinctrl-rockchip.c
> +++ b/drivers/pinctrl/pinctrl-rockchip.c
> @@ -2727,9 +2727,19 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
> return -EINVAL;
> }
>
> + /**
The typical multiline comment style is to use only 1 asterisk -- 2
asterisks usually denote something more formal, like kerneldoc.
> + * According to the TRM, we should keep irq disabled during programming
> + * interrupt capability to prevent spurious glitches on the interrupt
> + * lines to the interrupt controller.
> + */
It's also worth noting that this case may come up in
rockchip_irq_demux() for EDGE_BOTH triggers:
/*
* Triggering IRQ on both rising and falling edge
* needs manual intervention.
*/
if (bank->toggle_edge_mode & BIT(irq)) {
...
polarity = readl_relaxed(bank->reg_base +
GPIO_INT_POLARITY);
if (data & BIT(irq))
polarity &= ~BIT(irq);
else
polarity |= BIT(irq);
writel(polarity,
bank->reg_base + GPIO_INT_POLARITY);
AIUI, this case is not actually a problem, because this polarity
reconfiguration happens before we call generic_handle_irq(), so the
extra spurious interrupt is handled and cleared after this point. But it
seems like this should be noted somewhere in either the commit message,
the code comments, or both.
On the other hand...this also implies there may be a race condition
there, where we might lose an interrupt if there is an edge between the
re-configuration of the polarity in rockchip_irq_demux() and the
clearing/handling of the interrupt (handle_edge_irq() ->
chip->irq_ack()). If we have an edge between there, then we might ack
it, but leave the polarity such that we aren't ready for the next
(inverted) edge.
I'm not 100% sure about the above, so it might be good to verify it. But
I also expect this means there's really no way to 100% reliably
implement both-edge trigger types on hardware like this that doesn't
directly implement it. So I'm not sure what we'd do with that knowledge.
> + data = readl(bank->reg_base + GPIO_INTEN);
> + writel_relaxed(data & ~mask, gc->reg_base + GPIO_INTEN);
Not sure if this is a needless optimization: but couldn't you only
disable the interrupt (and make the level and polarity changes) only if
the level or polarity are actually changing? For example, it's possible
to end up here when changing from EDGE_BOTH to EDGE_RISING, but we might
not actually program a new value.
Brian
> +
> writel_relaxed(level, gc->reg_base + GPIO_INTTYPE_LEVEL);
> writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY);
>
> + writel_relaxed(data, gc->reg_base + GPIO_INTEN);
> +
> irq_gc_unlock(gc);
> raw_spin_unlock_irqrestore(&bank->slock, flags);
> clk_disable(bank->clk);
> --
> 2.11.0
>
>
^ permalink raw reply
* [PATCH v4 3/3] ARM: dts: sun7i: Add support for the Ainol AW1 tablet
From: Paul Kocialkowski @ 2018-05-07 22:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507220413.21990-1-contact@paulk.fr>
This adds support for the Ainol AW1, an A20-based 7" tablet from Ainol.
The following board-specific features are supported:
* LCD panel
* Backlight
* USB OTG
* Buttons
* Touchscreen (doesn't work without non-free firmware)
* Accelerometer
* Battery
The following are untested:
* Audio output
* Audio speakers
* USB via SPCI connector
The following are not supported:
* Wi-Fi
* Bluetooth
* NAND
* Audio via SPCI connector
* Audio via Bluetooth I2S
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/sun7i-a20-ainol-aw1.dts | 297 ++++++++++++++++++++++
2 files changed, 298 insertions(+)
create mode 100644 arch/arm/boot/dts/sun7i-a20-ainol-aw1.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 7e2424957809..4a80971f2bc9 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -946,6 +946,7 @@ dtb-$(CONFIG_MACH_SUN6I) += \
sun6i-a31s-sinovoip-bpi-m2.dtb \
sun6i-a31s-yones-toptech-bs1078-v2.dtb
dtb-$(CONFIG_MACH_SUN7I) += \
+ sun7i-a20-ainol-aw1.dtb \
sun7i-a20-bananapi.dtb \
sun7i-a20-bananapi-m1-plus.dtb \
sun7i-a20-bananapro.dtb \
diff --git a/arch/arm/boot/dts/sun7i-a20-ainol-aw1.dts b/arch/arm/boot/dts/sun7i-a20-ainol-aw1.dts
new file mode 100644
index 000000000000..9a732e4cd076
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-ainol-aw1.dts
@@ -0,0 +1,297 @@
+/*
+ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <contact@paulk.fr>
+ */
+
+/dts-v1/;
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+ model = "Ainol AW1";
+ compatible = "ainol,ainol-aw1", "allwinner,sun7i-a20";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+ brightness-levels = < 0 1 1 1 1 2 2 2
+ 2 3 3 3 3 4 4 4
+ 5 5 5 6 6 6 7 7
+ 8 8 8 9 9 9 10 10
+ 10 11 11 12 12 12 13 13
+ 14 14 14 15 15 16 16 17
+ 17 17 18 18 19 19 20 20
+ 21 21 21 22 22 23 23 24
+ 24 25 25 26 26 27 27 28
+ 28 29 30 30 31 31 32 32
+ 33 33 34 35 35 36 36 37
+ 38 38 39 39 40 41 41 42
+ 43 43 44 44 45 46 47 47
+ 48 49 49 50 51 51 52 53
+ 54 54 55 56 57 57 58 59
+ 60 61 61 62 63 64 65 65
+ 66 67 68 69 70 71 71 72
+ 73 74 75 76 77 78 79 80
+ 81 82 83 84 85 86 87 88
+ 89 90 91 92 93 94 95 96
+ 97 98 99 101 102 103 104 105
+ 106 108 109 110 111 112 114 115
+ 116 117 119 120 121 123 124 125
+ 127 128 129 131 132 133 135 136
+ 138 139 141 142 144 145 147 148
+ 150 151 153 154 156 157 159 161
+ 162 164 166 167 169 171 173 174
+ 176 178 180 181 183 185 187 189
+ 191 192 194 196 198 200 202 204
+ 206 208 210 212 214 216 219 221
+ 223 225 227 229 232 234 236 238
+ 241 242 244 246 248 250 253 255>;
+ default-brightness-level = <128>;
+ enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
+ };
+
+ panel: panel {
+ compatible = "innolux,at070tn90";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-supply = <&panel_power>;
+ backlight = <&backlight>;
+
+ port at 0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel_input: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&tcon0_out_panel>;
+ };
+ };
+ };
+
+ panel_power: panel_power {
+ compatible = "regulator-fixed";
+ regulator-name = "panel-power";
+ regulator-min-microvolt = <10400000>;
+ regulator-max-microvolt = <10400000>;
+ gpio = <&pio 7 8 GPIO_ACTIVE_HIGH>; /* PH8 */
+ enable-active-high;
+ regulator-boot-on;
+ };
+};
+
+&codec {
+ allwinner,pa-gpios = <&pio 7 15 GPIO_ACTIVE_HIGH>; /* PH15 */
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic at 34 {
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ lis3dh: accelerometer at 18 {
+ compatible = "st,lis3dh-accel";
+ reg = <0x18>;
+ vdd-supply = <®_vcc3v3>;
+ vddio-supply = <®_vcc3v3>;
+ st,drdy-int-pin = <1>;
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+ clock-frequency = <400000>;
+
+ gsl1680: touchscreen at 40 {
+ compatible = "silead,gsl1680";
+ reg = <0x40>;
+ interrupt-parent = <&pio>;
+ interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>; /* EINT21 (PH21) */
+ power-gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>; /* PH20 */
+ firmware-name = "gsl1680-ainol-aw1.fw";
+ touchscreen-size-x = <480>;
+ touchscreen-size-y = <800>;
+ touchscreen-swapped-x-y;
+ touchscreen-inverted-y;
+ silead,max-fingers = <5>;
+ };
+};
+
+&lradc {
+ vref-supply = <®_ldo2>;
+ status = "okay";
+
+ button at 571 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <571428>;
+ };
+
+ button at 761 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <761904>;
+ };
+
+ button at 952 {
+ label = "Home";
+ linux,code = <KEY_HOME>;
+ channel = <0>;
+ voltage = <952380>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins_a>;
+ status = "okay";
+};
+
+&tcon0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcd0_rgb666_pins>;
+ status = "okay";
+};
+
+&tcon0_out {
+ tcon0_out_panel: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&panel_input>;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usbphy {
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb0_vbus-supply = <®_usb0_vbus>;
+ usb1_vbus-supply = <®_usb1_vbus>;
+ usb2_vbus-supply = <®_usb2_vbus>;
+ status = "okay";
+};
+
+#include "axp209.dtsi"
+
+&battery_power_supply {
+ status = "okay";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1450000>;
+ regulator-name = "vdd-cpu";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-int-dll";
+};
+
+®_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+®_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+®_usb0_vbus {
+ status = "okay";
+};
+
+®_usb1_vbus {
+ status = "okay";
+};
+
+®_usb2_vbus {
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
--
2.17.0
^ permalink raw reply related
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