* [PATCH v6 2/5] Documentation: dt-bindings: phy: add phy_config for Rockchip USB Type-C PHY
From: Lin Huang @ 2018-05-21 9:37 UTC (permalink / raw)
To: seanpaul, airlied, zyw, kishon
Cc: dianders, briannorris, linux-rockchip, heiko, daniel.vetter,
jani.nikula, dri-devel, linux-arm-kernel, linux-kernel, eballetbo,
robh+dt, devicetree, Lin Huang
In-Reply-To: <1526895424-22894-1-git-send-email-hl@rock-chips.com>
If want to do training outside DP Firmware, need phy voltage swing
and pre_emphasis value.
Signed-off-by: Lin Huang <hl@rock-chips.com>
---
Changes in v2:
- None
Changes in v3:
- modify property description and add this property to Example
Changes in v4:
- None
Changes in v5:
- None
Changes in v6:
- change rockchip,phy_config to rockchip,phy-config and descript it in detail.
.../devicetree/bindings/phy/phy-rockchip-typec.txt | 36 +++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
index 960da7f..40d5e7a 100644
--- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
@@ -17,7 +17,11 @@ Required properties:
Optional properties:
- extcon : extcon specifier for the Power Delivery
-
+ - rockchip,phy-config : A list of voltage swing(mV) and pre-emphasis
+ (dB) pairs. They are 3 blocks of 4 entries and
+ correspond to s0p0 ~ s0p3, s1p0 ~ s1p3,
+ s2p0 ~ s2p3, s3p0 ~ s2p3 swing and pre-emphasis
+ values.
Required nodes : a sub-node is required for each port the phy provides.
The sub-node name is used to identify dp or usb3 port,
and shall be the following entries:
@@ -50,6 +54,21 @@ Example:
<&cru SRST_P_UPHY0_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
+ rockchip,phy-config = <0x2a 0x00>,
+ <0x1f 0x15>,
+ <0x14 0x22>,
+ <0x02 0x2b>,
+
+ <0x21 0x00>,
+ <0x12 0x15>,
+ <0x02 0x22>,
+ <0 0>,
+
+ <0x15 0x00>,
+ <0x00 0x15>,
+ <0 0>,
+ <0 0>;
+
tcphy0_dp: dp-port {
#phy-cells = <0>;
};
@@ -74,6 +93,21 @@ Example:
<&cru SRST_P_UPHY1_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
+ rockchip,phy-config = <0x2a 0x00>,
+ <0x1f 0x15>,
+ <0x14 0x22>,
+ <0x02 0x2b>,
+
+ <0x21 0x00>,
+ <0x12 0x15>,
+ <0x02 0x22>,
+ <0 0>,
+
+ <0x15 0x00>,
+ <0x00 0x15>,
+ <0 0>,
+ <0 0>;
+
tcphy1_dp: dp-port {
#phy-cells = <0>;
};
--
2.7.4
^ permalink raw reply related
* [PATCH v6 1/5] drm/rockchip: add transfer function for cdn-dp
From: Lin Huang @ 2018-05-21 9:37 UTC (permalink / raw)
To: seanpaul, airlied, zyw, kishon
Cc: dianders, briannorris, linux-rockchip, heiko, daniel.vetter,
jani.nikula, dri-devel, linux-arm-kernel, linux-kernel, eballetbo,
robh+dt, devicetree, Lin Huang
From: Chris Zhong <zyw@rock-chips.com>
We may support training outside firmware, so we need support
dpcd read/write to get the message or do some setting with
display.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Signed-off-by: Lin Huang <hl@rock-chips.com>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Reviewed-by: Enric Balletbo <enric.balletbo@collabora.com>
---
Changes in v2:
- update patch following Enric suggest
Changes in v3:
- None
Changes in v4:
- None
Changes in v5:
- None
Changes in v6:
- None
drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++++++++++++++++++++++----
drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 +
drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++++++++++++++++++++++++++++++----
drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++++++-
4 files changed, 122 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index c6fbdcd..cce64c1 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count)
u8 value;
*sink_count = 0;
- ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &value, 1);
- if (ret)
+ ret = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, &value, 1);
+ if (ret < 0)
return ret;
*sink_count = DP_GET_SINK_COUNT(value);
@@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
if (!cdn_dp_check_sink_connection(dp))
return -ENODEV;
- ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd,
- DP_RECEIVER_CAP_SIZE);
- if (ret) {
+ ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd,
+ sizeof(dp->dpcd));
+ if (ret < 0) {
DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret);
return ret;
}
@@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
if (!port || !dp->link.rate || !dp->link.num_lanes)
return false;
- if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status,
- DP_LINK_STATUS_SIZE)) {
+ if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) !=
+ DP_LINK_STATUS_SIZE) {
DRM_ERROR("Failed to get link status\n");
return false;
}
@@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb,
return NOTIFY_DONE;
}
+static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux,
+ struct drm_dp_aux_msg *msg)
+{
+ struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux);
+ int ret;
+ u8 status;
+
+ switch (msg->request & ~DP_AUX_I2C_MOT) {
+ case DP_AUX_NATIVE_WRITE:
+ case DP_AUX_I2C_WRITE:
+ case DP_AUX_I2C_WRITE_STATUS_UPDATE:
+ ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer,
+ msg->size);
+ break;
+ case DP_AUX_NATIVE_READ:
+ case DP_AUX_I2C_READ:
+ ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer,
+ msg->size);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ status = cdn_dp_get_aux_status(dp);
+ if (status == AUX_STATUS_ACK)
+ msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+ else if (status == AUX_STATUS_NACK)
+ msg->reply = DP_AUX_NATIVE_REPLY_NACK;
+ else if (status == AUX_STATUS_DEFER)
+ msg->reply = DP_AUX_NATIVE_REPLY_DEFER;
+
+ return ret;
+}
+
static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
{
struct cdn_dp_device *dp = dev_get_drvdata(dev);
@@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
dp->active = false;
dp->active_port = -1;
dp->fw_loaded = false;
+ dp->aux.name = "DP-AUX";
+ dp->aux.transfer = cdn_dp_aux_transfer;
+ dp->aux.dev = dev;
+
+ ret = drm_dp_aux_register(&dp->aux);
+ if (ret)
+ return ret;
INIT_WORK(&dp->event_work, cdn_dp_pd_event_work);
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index f57e296..46159b2 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -78,6 +78,7 @@ struct cdn_dp_device {
struct platform_device *audio_pdev;
struct work_struct event_work;
struct edid *edid;
+ struct drm_dp_aux aux;
struct mutex lock;
bool connected;
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
index eb3042c..979355d 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
@@ -221,7 +221,12 @@ static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr,
sizeof(field), field);
}
-int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
+/*
+ * Returns the number of bytes transferred on success, or a negative
+ * error code on failure. -ETIMEDOUT is returned if mailbox message was
+ * not send successfully;
+ */
+ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
{
u8 msg[5], reg[5];
int ret;
@@ -247,24 +252,41 @@ int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
goto err_dpcd_read;
ret = cdn_dp_mailbox_read_receive(dp, data, len);
+ if (!ret)
+ return len;
err_dpcd_read:
+ DRM_DEV_ERROR(dp->dev, "dpcd read failed: %d\n", ret);
return ret;
}
-int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
+#define CDN_AUX_HEADER_SIZE 5
+#define CDN_AUX_MSG_SIZE 20
+/*
+ * Returns the number of bytes transferred on success, or a negative error
+ * code on failure. -ETIMEDOUT is returned if mailbox message was not send
+ * success; -EINVAL is returned if get the wrong data size after message
+ * is sent
+ */
+ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
{
- u8 msg[6], reg[5];
+ u8 msg[CDN_AUX_MSG_SIZE + CDN_AUX_HEADER_SIZE];
+ u8 reg[CDN_AUX_HEADER_SIZE];
int ret;
- msg[0] = 0;
- msg[1] = 1;
+ if (WARN_ON(len > CDN_AUX_MSG_SIZE) || WARN_ON(len <= 0))
+ return -EINVAL;
+
+ msg[0] = (len >> 8) & 0xff;
+ msg[1] = len & 0xff;
msg[2] = (addr >> 16) & 0xff;
msg[3] = (addr >> 8) & 0xff;
msg[4] = addr & 0xff;
- msg[5] = value;
+
+ memcpy(msg + CDN_AUX_HEADER_SIZE, data, len);
+
ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD,
- sizeof(msg), msg);
+ CDN_AUX_HEADER_SIZE + len, msg);
if (ret)
goto err_dpcd_write;
@@ -277,8 +299,12 @@ int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
if (ret)
goto err_dpcd_write;
- if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4]))
+ if ((len != (reg[0] << 8 | reg[1])) ||
+ (addr != (reg[2] << 16 | reg[3] << 8 | reg[4]))) {
ret = -EINVAL;
+ } else {
+ return len;
+ }
err_dpcd_write:
if (ret)
@@ -286,6 +312,33 @@ int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
return ret;
}
+int cdn_dp_get_aux_status(struct cdn_dp_device *dp)
+{
+ u8 status;
+ int ret;
+
+ ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX,
+ DPTX_GET_LAST_AUX_STAUS, 0, NULL);
+ if (ret)
+ goto err_get_hpd;
+
+ ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
+ DPTX_GET_LAST_AUX_STAUS,
+ sizeof(status));
+ if (ret)
+ goto err_get_hpd;
+
+ ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status));
+ if (ret)
+ goto err_get_hpd;
+
+ return status;
+
+err_get_hpd:
+ DRM_DEV_ERROR(dp->dev, "get aux status failed: %d\n", ret);
+ return ret;
+}
+
int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
u32 i_size, const u32 *d_mem, u32 d_size)
{
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
index c4bbb4a83..6580b11 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
@@ -328,6 +328,13 @@
#define GENERAL_BUS_SETTINGS 0x03
#define GENERAL_TEST_ACCESS 0x04
+/* AUX status*/
+#define AUX_STATUS_ACK 0
+#define AUX_STATUS_NACK 1
+#define AUX_STATUS_DEFER 2
+#define AUX_STATUS_SINK_ERROR 3
+#define AUX_STATUS_BUS_ERROR 4
+
#define DPTX_SET_POWER_MNG 0x00
#define DPTX_SET_HOST_CAPABILITIES 0x01
#define DPTX_GET_EDID 0x02
@@ -469,8 +476,11 @@ int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip);
int cdn_dp_event_config(struct cdn_dp_device *dp);
u32 cdn_dp_get_event(struct cdn_dp_device *dp);
int cdn_dp_get_hpd_status(struct cdn_dp_device *dp);
-int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value);
-int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len);
+ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr,
+ u8 *data, u16 len);
+ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr,
+ u8 *data, u16 len);
+int cdn_dp_get_aux_status(struct cdn_dp_device *dp);
int cdn_dp_get_edid_block(void *dp, u8 *edid,
unsigned int block, size_t length);
int cdn_dp_train_link(struct cdn_dp_device *dp);
--
2.7.4
^ permalink raw reply related
* Re: [v4 2/6] dmaengine: fsl-qdma: Add qDMA controller driver for Layerscape SoCs
From: Vinod Koul @ 2018-05-21 9:09 UTC (permalink / raw)
To: Wen He
Cc: dmaengine@vger.kernel.org, robh+dt@kernel.org,
devicetree@vger.kernel.org, Leo Li, Jiafei Pan, Jiaheng Fan
In-Reply-To: <DB6PR0401MB250380A95367C42C1BC79595E2900@DB6PR0401MB2503.eurprd04.prod.outlook.com>
On 18-05-18, 10:04, Wen He wrote:
> > > > > +u64 pre_addr, pre_queue;
> > > >
> > > > why do we have a global?
> > >
> > > Let's us see qDMA that how is works?
> > >
> > > First, the status notification for DMA jobs are reported back to the status
> > queue.
> > > Status information is carried within the command descriptor
> > > status/command field, bits 120-127. The command descriptor dequeue
> > > pointer advances only after the transaction has completed and the status
> > information field has been updated.
> > >
> > > Then, the command descriptor address field wiil pointer to the command
> > > descriptor in its original format. It is the responsibity of the
> > > address of the status queue consumer to deallocate buffers as needed when
> > the command descriptor address pointer is non-zero.
> > >
> > > More details of the Status Queue can be found in QorIQ Layerscape Soc
> > datasheet.
> > >
> > > So, these variable is used to record latest value that command
> > > descriptor queue and status field.
> > >
> > > Every time variables value is zero when set these variable to local, that's not
> > what I want.
> >
> > Why not store them in driver context?
> >
>
> okay, maybe I should remove these variable to private struct?
Yes that would be better
> > > > > + memset(sg_block->virt_addr, 0,
> > > > > + FSL_QDMA_EXPECT_SG_ENTRY_NUM * 16);
> > > >
> > > > why FSL_QDMA_EXPECT_SG_ENTRY_NUM * 16? and not what you
> > allocated?
> > > >
> > >
> > > see line 497.
> > > The sg_pool buffer size created is FSL_QDMA_EXPECT_SG_ENTRY_NUM *
> > 16.
> >
> > Please document this
> >
> Add comment to this?
yup, explaining where 16 is coming from
--
~Vinod
^ permalink raw reply
* Re: [PATCH v8 10/15] cpufreq: Add Kryo CPU scaling driver
From: Viresh Kumar @ 2018-05-21 9:05 UTC (permalink / raw)
To: ilialin
Cc: mturquette, sboyd, robh, mark.rutland, nm, lgirdwood, broonie,
andy.gross, david.brown, catalin.marinas, will.deacon, rjw,
linux-clk, devicetree, linux-kernel, linux-pm, linux-arm-msm,
linux-soc, linux-arm-kernel, rnayak, amit.kucheria,
nicolas.dechesne, celster, tfinkel
In-Reply-To: <000501d3f0e2$23500c00$69f02400$@codeaurora.org>
On 21-05-18, 12:00, ilialin@codeaurora.org wrote:
> Final version (addressing Russel's comment as well):
Sorry, can't review it like this. At least you should be posting your
diff here and you also need to do that from a sane email client like
mutt, which wouldn't auto-fix/update the code. Doing it from gmail or
thunderbird will ofcourse screw it.
Or a simple way is to send the patch again (alone) using in-reply-to
field.
--
viresh
^ permalink raw reply
* Re: [PATCH v2 0/2] Add support for QCOM cpufreq FW driver
From: Viresh Kumar @ 2018-05-21 9:02 UTC (permalink / raw)
To: Taniya Das
Cc: Rafael J. Wysocki, linux-kernel, linux-pm, Stephen Boyd, robh,
Rajendra Nayak, Amit Nischal, devicetree, skannan, amit.kucheria
In-Reply-To: <cb15a4db-77cd-8063-f323-652c6b03306e@codeaurora.org>
On 21-05-18, 13:05, Taniya Das wrote:
> Hello Viresh,
>
> Sure, will do it next time. Hope updating the fixes in this email is fine.
> Do let me know in case you need me to send it across again the series with
> cover letter updated.
>
> On 5/21/2018 11:35 AM, Viresh Kumar wrote:
> > On 19-05-18, 23:04, Taniya Das wrote:
> > > [v2]
> > > * Address comments given in v0 series.
> >
> > That's not how you do it. You need to explain every change in enough
> > detail here so that the reviewers don't need to go to their previous
> > emails to see what changed.
> >
> Fixes in [v2]
> * Fixed the alignment issues in "qcom_cpufreq_fw_target_index" for
> dev_err and also for "qcom_cpu_resources_init".
> * Removed ret = 0 from qcom_get_related_cpus and added to check for
> cpu_mask_empty to return -ENOENT.
> * Fixes qcom_cpu_resources_init function
> * Remove initialization of 'index'
> * Check for valid 'c'
> * Removed initialization of 'prev_cc' from 'qcom_read_lut'.
> * Remove initialization of 'ret' from function qcom_resources_init and add
> return -ENODEV based on 'of_get_available_child_count'.
> * Removed initialization of 'rc' from qcom_cpufreq_fw_driver_probe
> * Removed module_exit as this driver would not be used as module, also
> updated the Kconfig to bool from tristate.
> * Updated the subsystem in device tree bindings.
That's what it should look like. Thanks.
--
viresh
^ permalink raw reply
* Re: [PATCH v2 2/2] cpufreq: qcom-fw: Add support for QCOM cpufreq FW driver
From: Viresh Kumar @ 2018-05-21 9:01 UTC (permalink / raw)
To: Taniya Das
Cc: Rafael J. Wysocki, linux-kernel, linux-pm, Stephen Boyd, robh,
Rajendra Nayak, Amit Nischal, devicetree, skannan, amit.kucheria
In-Reply-To: <1526751291-17873-3-git-send-email-tdas@codeaurora.org>
On 19-05-18, 23:04, Taniya Das wrote:
> The CPUfreq FW present in some QCOM chipsets offloads the steps necessary
> for changing the frequency of CPUs. The driver implements the cpufreq
> driver interface for this firmware.
>
> Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
> Signed-off-by: Taniya Das <tdas@codeaurora.org>
> ---
> drivers/cpufreq/Kconfig.arm | 9 ++
> drivers/cpufreq/Makefile | 1 +
> drivers/cpufreq/qcom-cpufreq-fw.c | 317 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 327 insertions(+)
> create mode 100644 drivers/cpufreq/qcom-cpufreq-fw.c
>
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 96b35b8..571f6b4 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -301,3 +301,12 @@ config ARM_PXA2xx_CPUFREQ
> This add the CPUFreq driver support for Intel PXA2xx SOCs.
>
> If in doubt, say N.
> +
> +config ARM_QCOM_CPUFREQ_FW
> + bool "QCOM CPUFreq FW driver"
During last review I didn't say that this driver shouldn't be a
module, but that you need to fix things to make it a module. I am fine
though if you don't want this to be a module ever.
> + help
> + Support for the CPUFreq FW driver.
> + The CPUfreq FW preset in some QCOM chipsets offloads the steps
> + necessary for changing the frequency of CPUs. The driver
> + implements the cpufreq driver interface for this firmware.
> + Say Y if you want to support CPUFreq FW.
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 8d24ade..a3edbce 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -85,6 +85,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
> obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o
> obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o
> obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
> +obj-$(CONFIG_ARM_QCOM_CPUFREQ_FW) += qcom-cpufreq-fw.o
>
>
> ##################################################################################
> diff --git a/drivers/cpufreq/qcom-cpufreq-fw.c b/drivers/cpufreq/qcom-cpufreq-fw.c
> new file mode 100644
> index 0000000..0e66de0
> --- /dev/null
> +++ b/drivers/cpufreq/qcom-cpufreq-fw.c
> @@ -0,0 +1,317 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018, The Linux Foundation. All rights reserved.
> + */
> +
> +#include <linux/cpufreq.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +
> +#define INIT_RATE 300000000UL
> +#define XO_RATE 19200000UL
> +#define LUT_MAX_ENTRIES 40U
> +#define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16)
> +#define LUT_ROW_SIZE 32
> +
> +struct cpufreq_qcom {
> + struct cpufreq_frequency_table *table;
> + struct device *dev;
> + void __iomem *perf_base;
> + void __iomem *lut_base;
> + cpumask_t related_cpus;
> + unsigned int max_cores;
> +};
> +
> +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS];
> +
> +static int
> +qcom_cpufreq_fw_target_index(struct cpufreq_policy *policy, unsigned int index)
> +{
> + struct cpufreq_qcom *c = policy->driver_data;
> +
> + if (index >= LUT_MAX_ENTRIES) {
> + dev_err(c->dev,
> + "Passing an index (%u) that's greater than max (%d)\n",
> + index, LUT_MAX_ENTRIES - 1);
> + return -EINVAL;
> + }
This is never going to happen unless there is a bug in cpufreq core.
You are allocating only 40 entries for the cpufreq table and this will
always be 0-39. None of the other drivers is checking this I believe
and neither should you. This is the only routine which will get call
very frequently and we better not add unnecessary stuff here.
> + writel_relaxed(index, c->perf_base);
> +
> + /* Make sure the write goes through before proceeding */
> + mb();
Btw what happens right after this is done ? Are we guaranteed that the
frequency is updated in the hardware after this ? What about enabling
fast-switch for your platform ? Look at drivers/cpufreq/scmi-cpufreq.c
to see how that is done.
> + return 0;
> +}
> +
> +static unsigned int qcom_cpufreq_fw_get(unsigned int cpu)
> +{
> + struct cpufreq_qcom *c;
> + unsigned int index;
> +
> + c = qcom_freq_domain_map[cpu];
> + if (!c)
> + return -ENODEV;
Return 0 on error here.
> +
> + index = readl_relaxed(c->perf_base);
> + index = min(index, LUT_MAX_ENTRIES - 1);
Will the hardware ever read a value over 39 here ?
> +
> + return c->table[index].frequency;
> +}
> +
> +static int qcom_cpufreq_fw_cpu_init(struct cpufreq_policy *policy)
> +{
> + struct cpufreq_qcom *c;
> +
> + c = qcom_freq_domain_map[policy->cpu];
> + if (!c) {
> + pr_err("No scaling support for CPU%d\n", policy->cpu);
> + return -ENODEV;
> + }
> +
> + cpumask_copy(policy->cpus, &c->related_cpus);
> + policy->freq_table = c->table;
> + policy->driver_data = c;
> +
> + return 0;
> +}
> +
> +static struct freq_attr *qcom_cpufreq_fw_attr[] = {
> + &cpufreq_freq_attr_scaling_available_freqs,
> + &cpufreq_freq_attr_scaling_boost_freqs,
> + NULL
> +};
> +
> +static struct cpufreq_driver cpufreq_qcom_fw_driver = {
> + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
> + CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
> + .verify = cpufreq_generic_frequency_table_verify,
> + .target_index = qcom_cpufreq_fw_target_index,
> + .get = qcom_cpufreq_fw_get,
> + .init = qcom_cpufreq_fw_cpu_init,
> + .name = "qcom-cpufreq-fw",
> + .attr = qcom_cpufreq_fw_attr,
> + .boost_enabled = true,
> +};
> +
> +static int qcom_read_lut(struct platform_device *pdev,
> + struct cpufreq_qcom *c)
> +{
> + struct device *dev = &pdev->dev;
> + u32 data, src, lval, i, core_count, prev_cc;
> +
> + c->table = devm_kcalloc(dev, LUT_MAX_ENTRIES + 1,
> + sizeof(*c->table), GFP_KERNEL);
> + if (!c->table)
> + return -ENOMEM;
> +
> + for (i = 0; i < LUT_MAX_ENTRIES; i++) {
> + data = readl_relaxed(c->lut_base + i * LUT_ROW_SIZE);
> + src = ((data & GENMASK(31, 30)) >> 30);
> + lval = (data & GENMASK(7, 0));
> + core_count = CORE_COUNT_VAL(data);
> +
> + if (!src)
> + c->table[i].frequency = INIT_RATE / 1000;
> + else
> + c->table[i].frequency = XO_RATE * lval / 1000;
> +
> + c->table[i].driver_data = c->table[i].frequency;
Why do you need to use driver_data here? Why can't you simple use
frequency field in the below conditional expressions ?
> +
> + dev_dbg(dev, "index=%d freq=%d, core_count %d\n",
> + i, c->table[i].frequency, core_count);
> +
> + if (core_count != c->max_cores)
> + c->table[i].frequency = CPUFREQ_ENTRY_INVALID;
> +
> + /*
> + * Two of the same frequencies with the same core counts means
> + * end of table.
> + */
> + if (i > 0 && c->table[i - 1].driver_data ==
> + c->table[i].driver_data && prev_cc == core_count) {
> + struct cpufreq_frequency_table *prev = &c->table[i - 1];
> +
> + if (prev->frequency == CPUFREQ_ENTRY_INVALID) {
There can only be a single boost frequency at max ?
> + prev->flags = CPUFREQ_BOOST_FREQ;
> + prev->frequency = prev->driver_data;
Okay you are using driver_data as a local variable to keep this value
safe which you might have overwritten. Maybe use a simple variable
prev_freq for this. It would be much more readable in that case and
you wouldn't end up abusing the driver_data field.
> + }
> +
> + break;
> + }
> + prev_cc = core_count;
> + }
> + c->table[i].frequency = CPUFREQ_TABLE_END;
Wouldn't you end up writing on c->table[40].frequency here if there
are 40 frequency value present ?
> +
> + return 0;
> +}
> +
> +static int qcom_get_related_cpus(struct device_node *np, struct cpumask *m)
> +{
> + struct device_node *dev_phandle;
> + struct device *cpu_dev;
> + int cpu, i = 0;
> +
> + dev_phandle = of_parse_phandle(np, "qcom,cpulist", i++);
> + while (dev_phandle) {
> + for_each_possible_cpu(cpu) {
> + cpu_dev = get_cpu_device(cpu);
> + if (cpu_dev && cpu_dev->of_node == dev_phandle) {
You can use of_cpu_device_node_get() here.
> + cpumask_set_cpu(cpu, m);
> + break;
> + }
> + }
> + dev_phandle = of_parse_phandle(np, "qcom,cpulist", i++);
> + }
> +
> + if (cpumask_empty(m))
> + return -ENOENT;
> +
> + return 0;
> +}
> +
> +static int qcom_cpu_resources_init(struct platform_device *pdev,
> + struct device_node *np)
> +{
> + struct cpufreq_qcom *c;
> + struct resource res;
> + struct device *dev = &pdev->dev;
> + void __iomem *en_base;
> + int cpu, index, ret;
> +
> + c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
> + if (!c)
> + return -ENOMEM;
> +
> + index = of_property_match_string(np, "reg-names", "en_base");
> + if (index < 0)
> + return index;
> +
> + if (of_address_to_resource(np, index, &res))
> + return -ENOMEM;
> +
> + en_base = devm_ioremap(dev, res.start, resource_size(&res));
> + if (!en_base) {
> + dev_err(dev, "Unable to map %s en-base\n", np->name);
> + return -ENOMEM;
> + }
> +
> + /* FW should be in enabled state to proceed */
> + if (!(readl_relaxed(en_base) & 0x1)) {
> + dev_err(dev, "%s firmware not enabled\n", np->name);
> + return -ENODEV;
> + }
> +
> + devm_iounmap(&pdev->dev, en_base);
> +
> + index = of_property_match_string(np, "reg-names", "perf_base");
> + if (index < 0)
> + return index;
> +
> + if (of_address_to_resource(np, index, &res))
> + return -ENOMEM;
> +
> + c->perf_base = devm_ioremap(dev, res.start, resource_size(&res));
> + if (!c->perf_base) {
> + dev_err(dev, "Unable to map %s perf-base\n", np->name);
> + return -ENOMEM;
> + }
> +
> + index = of_property_match_string(np, "reg-names", "lut_base");
> + if (index < 0)
> + return index;
> +
> + if (of_address_to_resource(np, index, &res))
> + return -ENOMEM;
> +
> + c->lut_base = devm_ioremap(dev, res.start, resource_size(&res));
> + if (!c->lut_base) {
> + dev_err(dev, "Unable to map %s lut-base\n", np->name);
> + return -ENOMEM;
> + }
> +
> + ret = qcom_get_related_cpus(np, &c->related_cpus);
> + if (ret) {
> + dev_err(dev, "%s failed to get core phandles\n", np->name);
> + return ret;
> + }
> +
> + c->max_cores = cpumask_weight(&c->related_cpus);
> +
> + ret = qcom_read_lut(pdev, c);
> + if (ret) {
> + dev_err(dev, "%s failed to read LUT\n", np->name);
> + return ret;
> + }
> +
> + for_each_cpu(cpu, &c->related_cpus)
> + qcom_freq_domain_map[cpu] = c;
> +
> + return 0;
> +}
> +
> +static int qcom_resources_init(struct platform_device *pdev)
> +{
> + struct device_node *np;
> + int ret;
> +
> + if (!of_get_available_child_count(pdev->dev.of_node))
> + return -ENODEV;
> +
> + for_each_available_child_of_node(pdev->dev.of_node, np) {
> + if (of_device_is_compatible(np, "cpufreq")) {
> + ret = qcom_cpu_resources_init(pdev, np);
> + if (ret)
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int qcom_cpufreq_fw_driver_probe(struct platform_device *pdev)
> +{
> + int rc;
> +
> + /* Get the bases of cpufreq for domains */
> + rc = qcom_resources_init(pdev);
> + if (rc) {
> + dev_err(&pdev->dev, "CPUFreq resource init failed\n");
> + return rc;
> + }
> +
> + rc = cpufreq_register_driver(&cpufreq_qcom_fw_driver);
> + if (rc) {
> + dev_err(&pdev->dev, "CPUFreq FW driver failed to register\n");
> + return rc;
> + }
> +
> + dev_info(&pdev->dev, "QCOM CPUFreq FW driver inited\n");
> +
> + return 0;
> +}
> +
> +static const struct of_device_id match_table[] = {
> + { .compatible = "qcom,cpufreq-fw" },
> + {}
> +};
> +
> +static struct platform_driver qcom_cpufreq_fw_driver = {
> + .probe = qcom_cpufreq_fw_driver_probe,
> + .driver = {
> + .name = "qcom-cpufreq-fw",
> + .of_match_table = match_table,
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init qcom_cpufreq_fw_init(void)
> +{
> + return platform_driver_register(&qcom_cpufreq_fw_driver);
> +}
> +subsys_initcall(qcom_cpufreq_fw_init);
> +
> +MODULE_DESCRIPTION("QCOM CPU Frequency FW");
> +MODULE_LICENSE("GPL v2");
> --
> Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member
> of the Code Aurora Forum, hosted by the Linux Foundation.
--
viresh
^ permalink raw reply
* RE: [PATCH v8 10/15] cpufreq: Add Kryo CPU scaling driver
From: ilialin @ 2018-05-21 9:00 UTC (permalink / raw)
To: 'Viresh Kumar'
Cc: mturquette, sboyd, robh, mark.rutland, nm, lgirdwood, broonie,
andy.gross, david.brown, catalin.marinas, will.deacon, rjw,
linux-clk, devicetree, linux-kernel, linux-pm, linux-arm-msm,
linux-soc, linux-arm-kernel, rnayak, amit.kucheria,
nicolas.dechesne, celster, tfinkel
In-Reply-To: <20180521044938.bnr2sdkmvdorfxqm@vireshk-i7>
Final version (addressing Russel's comment as well):
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
/*
* In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors,
* the CPU frequency subset and voltage value of each OPP varies
* based on the silicon variant in use. Qualcomm Process Voltage Scaling
Tables
* defines the voltage and frequency value based on the msm-id in SMEM
* and speedbin blown in the efuse combination.
* The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the
SoC
* to provide the OPP framework with required information.
* This is used to determine the voltage and frequency value for each OPP of
* operating-points-v2 table when it is parsed by the OPP framework.
*/
#include <linux/cpu.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>
#define MSM_ID_SMEM 137
#define SILVER_LEAD 0
#define GOLD_LEAD 2
enum _msm_id {
MSM8996V3 = 0xF6ul,
APQ8096V3 = 0x123ul,
MSM8996SG = 0x131ul,
APQ8096SG = 0x138ul,
};
enum _msm8996_version {
MSM8996_V3,
MSM8996_SG,
NUM_OF_MSM8996_VERSIONS,
};
static enum _msm8996_version __init qcom_cpufreq_kryo_get_msm_id(void)
{
size_t len;
u32 *msm_id;
enum _msm8996_version version;
msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len);
/* The first 4 bytes are format, next to them is the actual msm-id
*/
msm_id++;
switch ((enum _msm_id)*msm_id) {
case MSM8996V3:
case APQ8096V3:
version = MSM8996_V3;
break;
case MSM8996SG:
case APQ8096SG:
version = MSM8996_SG;
break;
default:
version = NUM_OF_MSM8996_VERSIONS;
}
return version;
}
static int __init qcom_cpufreq_kryo_driver_init(void)
{
struct device *cpu_dev_silver, *cpu_dev_gold;
struct opp_table *opp_silver, *opp_gold;
enum _msm8996_version msm8996_version;
struct nvmem_cell *speedbin_nvmem;
struct platform_device *pdev;
struct device_node *np;
u8 *speedbin;
u32 versions;
size_t len;
int ret;
cpu_dev_silver = get_cpu_device(SILVER_LEAD);
if (NULL == cpu_dev_silver)
return -ENODEV;
cpu_dev_gold = get_cpu_device(SILVER_LEAD);
if (NULL == cpu_dev_gold)
return -ENODEV;
msm8996_version = qcom_cpufreq_kryo_get_msm_id();
if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
dev_err(cpu_dev_silver, "Not Snapdragon 820/821!");
return -ENODEV;
}
np = dev_pm_opp_of_get_opp_desc_node(cpu_dev_silver);
if (IS_ERR(np))
return PTR_ERR(np);
if (!of_device_is_compatible(np, "operating-points-v2-kryo-cpu")) {
ret = -ENOENT;
goto free_np;
}
speedbin_nvmem = of_nvmem_cell_get(np, NULL);
if (IS_ERR(speedbin_nvmem)) {
ret = PTR_ERR(speedbin_nvmem);
dev_err(cpu_dev_silver, "Could not get nvmem cell: %d\n",
ret);
goto free_np;
}
speedbin = nvmem_cell_read(speedbin_nvmem, &len);
nvmem_cell_put(speedbin_nvmem);
switch (msm8996_version) {
case MSM8996_V3:
versions = 1 << (unsigned int)(*speedbin);
break;
case MSM8996_SG:
versions = 1 << ((unsigned int)(*speedbin) + 4);
break;
default:
BUG();
break;
}
opp_silver =
dev_pm_opp_set_supported_hw(cpu_dev_silver,&versions,1);
if (IS_ERR(opp_silver)) {
dev_err(cpu_dev_silver, "Failed to set supported
hardware\n");
ret = PTR_ERR(opp_silver);
goto free_np;
}
opp_gold = dev_pm_opp_set_supported_hw(cpu_dev_gold,&versions,1);
if (IS_ERR(opp_gold)) {
dev_err(cpu_dev_gold, "Failed to set supported hardware\n");
ret = PTR_ERR(opp_gold);
goto free_opp_silver;
}
pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
if (!IS_ERR(pdev))
return 0;
ret = PTR_ERR(pdev);
dev_err(cpu_dev_silver, "Failed to register platform device\n");
dev_pm_opp_put_supported_hw(opp_gold);
free_opp_silver:
dev_pm_opp_put_supported_hw(opp_silver);
free_np:
of_node_put(np);
return ret;
}
late_initcall(qcom_cpufreq_kryo_driver_init);
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver");
MODULE_LICENSE("GPL v2");
> -----Original Message-----
> From: Viresh Kumar <viresh.kumar@linaro.org>
> Sent: Monday, May 21, 2018 07:50
> To: ilialin@codeaurora.org
> Cc: mturquette@baylibre.com; sboyd@kernel.org; robh@kernel.org;
> mark.rutland@arm.com; nm@ti.com; lgirdwood@gmail.com;
> broonie@kernel.org; andy.gross@linaro.org; david.brown@linaro.org;
> catalin.marinas@arm.com; will.deacon@arm.com; rjw@rjwysocki.net; linux-
> clk@vger.kernel.org; devicetree@vger.kernel.org; linux-
> kernel@vger.kernel.org; linux-pm@vger.kernel.org; linux-arm-
> msm@vger.kernel.org; linux-soc@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org; rnayak@codeaurora.org;
> amit.kucheria@linaro.org; nicolas.dechesne@linaro.org;
> celster@codeaurora.org; tfinkel@codeaurora.org
> Subject: Re: [PATCH v8 10/15] cpufreq: Add Kryo CPU scaling driver
>
> On 19-05-18, 14:45, ilialin@codeaurora.org wrote:
> > Hi Viresh,
> >
> > If I send patches in reply, it will produce new patches, instead of
> > answers in the thread. Please find below the file dump.
>
> There is one email from you which appears to be just fine and appears to
be
> in reply to this thread only. Maybe its your email client that screwed it
up for
> you ? Things look good in mutt.
>
> --
> viresh
^ permalink raw reply
* [PATCH] clk: Add driver for MAX9485
From: Daniel Mack @ 2018-05-21 8:58 UTC (permalink / raw)
To: mturquette, sboyd; +Cc: linux-clk, devicetree, Daniel Mack, Daniel Mack
From: Daniel Mack <zonque@gmail.com>
This patch adds a driver for MAX9485, a programmable audio clock generator.
The device requires a 27.000 MHz clock input. It can provide a gated
buffered output of its input clock and two gated outputs of a PLL that can
generate one out of 16 discrete frequencies. There is only one PLL however,
so the two gated outputs will always have the same frequency but they can
be switched individually.
The driver for this device exposes 4 clocks in total:
- MAX9485_MCLKOUT: A gated, buffered output of the input clock
- MAX9485_CLKOUT: A PLL that can be configured to 16 different
discrete frequencies
- MAX9485_CLKOUT[1,2]: Two gated outputs for MAX9485_CLKOUT
Some PLL output frequencies can be achieved with different register
settings. The driver will select the one with lowest jitter in such cases.
Signed-off-by: Daniel Mack <daniel@zonque.org>
---
.../devicetree/bindings/clock/maxim,max9485.txt | 59 ++++
drivers/clk/Kconfig | 8 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-max9485.c | 379 +++++++++++++++++++++
include/dt-bindings/clock/maxim,max9485.h | 19 ++
5 files changed, 466 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/maxim,max9485.txt
create mode 100644 drivers/clk/clk-max9485.c
create mode 100644 include/dt-bindings/clock/maxim,max9485.h
diff --git a/Documentation/devicetree/bindings/clock/maxim,max9485.txt b/Documentation/devicetree/bindings/clock/maxim,max9485.txt
new file mode 100644
index 000000000000..43713031be2c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/maxim,max9485.txt
@@ -0,0 +1,59 @@
+Devicetree bindings for Maxim MAX9485 Programmable Audio Clock Generator
+
+The driver for this device exposes 4 clocks in total:
+
+- MAX9485_MCLKOUT: A gated, buffered output of the input clock of 27 MHz
+- MAX9485_CLKOUT: A PLL that can be configured to 16 different discrete
+ frequencies
+- MAX9485_CLKOUT[1,2]: Two gated outputs for MAX9485_CLKOUT
+
+MAX9485_CLKOUT[1,2] are children of MAX9485_CLKOUT which upchain all rate set
+requests.
+
+Required properties:
+- compatible: "maxim,max9485"
+- clocks: Input clock, must provice 27.000 MHz
+- clock-names: Must be set to "xclk"
+- #clock-cells: From common clock binding; shall be set to 1
+
+Optional properties:
+- reset-gpio: GPIO descriptor connected to the #RESET input pin
+- vdd-supply: A regulator node for Vdd
+- clock-output-names: Name of output clocks, as defined in common clock
+ bindings
+
+If not explicitly set, the output names are "mclkout", "clkout", "clkout1"
+and "clkout2".
+
+Clocks are defined as preprocessor macros in the dt-binding header.
+
+Example:
+
+ #include <dt-bindings/clock/maxim,max9485.h>
+
+ xo_27mhz: xo_27mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+
+ &i2c0 {
+ max9485: max9485@63 {
+ compatible = "maxim,max9485";
+ clock-names = "xclk";
+ clocks = <&xo_27mhz>;
+ reg = <0x63>;
+ reset-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
+ vdd-supply = <&3v3_reg>;
+ #clock-cells = <1>;
+ };
+ };
+
+ // Clock consumer node
+
+ foo@0 {
+ compatible = "bar,foo";
+ /* ... */
+ clock-names = "foo-intput-clk";
+ clocks = <&max9485 MAX9485_CLKOUT1>;
+ };
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 34968a381d0f..f8ab54c41d16 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -45,6 +45,14 @@ config COMMON_CLK_MAX77686
This driver supports Maxim 77620/77686/77802 crystal oscillator
clock.
+config COMMON_CLK_MAX9485
+ tristate "Clock driver for Maxim 9485 Programmable Clock Generator"
+ depends on I2C
+ depends on OF
+ depends on GPIOLIB || COMPILE_TEST
+ ---help---
+ This driver supports Maxim 9485 Programmable Audio Clock Generator
+
config COMMON_CLK_RK808
tristate "Clock driver for RK805/RK808/RK818"
depends on MFD_RK808
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index de6d06ac790b..27417ba3c1df 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
diff --git a/drivers/clk/clk-max9485.c b/drivers/clk/clk-max9485.c
new file mode 100644
index 000000000000..d6c0d51d2d72
--- /dev/null
+++ b/drivers/clk/clk-max9485.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * clk-max9485.c: MAX9485 Programmable Audio Clock Generator
+ *
+ * (c) 2018 Daniel Mack <daniel@zonque.org>
+ *
+ * References:
+ * MAX9485 Datasheet
+ * http://www.maximintegrated.com/datasheet/index.mvp/id/4421
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/clkdev.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
+
+#include <dt-bindings/clock/maxim,max9485.h>
+
+#define MAX9485_INPUT_FREQ 27000000UL
+#define MAX9485_NUM_CLKS 4
+
+/* This chip has only one register of 8 bit width. */
+
+enum {
+ MAX9485_FS_12KHZ = 0 << 0,
+ MAX9485_FS_32KHZ = 1 << 0,
+ MAX9485_FS_44_1KHZ = 2 << 0,
+ MAX9485_FS_48KHZ = 3 << 0,
+};
+
+enum {
+ MAX9485_SCALE_256 = 0 << 2,
+ MAX9485_SCALE_384 = 1 << 2,
+ MAX9485_SCALE_768 = 2 << 2,
+};
+
+#define MAX9485_DOUBLE BIT(4)
+#define MAX9485_CLKOUT1_ENABLE BIT(5)
+#define MAX9485_CLKOUT2_ENABLE BIT(6)
+#define MAX9485_MCLK_ENABLE BIT(7)
+#define MAX9485_FREQ_MASK 0x1f
+
+struct max9485_rate {
+ unsigned long out;
+ u8 reg_value;
+};
+
+/*
+ * Ordered by frequency. For frequency the hardware can generate with
+ * multiple settings, only the one with lowest jitter is listed.
+ */
+static const struct max9485_rate max9485_rates[] = {
+ { 3072000, MAX9485_FS_12KHZ | MAX9485_SCALE_256 },
+ { 4608000, MAX9485_FS_12KHZ | MAX9485_SCALE_384 },
+ { 8192000, MAX9485_FS_32KHZ | MAX9485_SCALE_256 },
+ { 9126000, MAX9485_FS_12KHZ | MAX9485_SCALE_768 },
+ { 11289600, MAX9485_FS_44_1KHZ | MAX9485_SCALE_256 },
+ { 12288000, MAX9485_FS_48KHZ | MAX9485_SCALE_256 },
+ { 16384000, MAX9485_FS_32KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE },
+ { 16934400, MAX9485_FS_44_1KHZ | MAX9485_SCALE_384 },
+ { 18384000, MAX9485_FS_48KHZ | MAX9485_SCALE_384 },
+ { 22579200, MAX9485_FS_44_1KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE },
+ { 24576000, MAX9485_FS_48KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE },
+ { 33868800, MAX9485_FS_44_1KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE },
+ { 36864000, MAX9485_FS_48KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE },
+ { 49152000, MAX9485_FS_32KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE },
+ { 67737600, MAX9485_FS_44_1KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE },
+ { 73728000, MAX9485_FS_48KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE },
+ { } /* sentinel */
+};
+
+struct max9485_driver_data;
+
+struct max9485_clk_hw {
+ struct clk_hw hw;
+ struct clk_init_data init;
+ u8 enable_bit;
+ struct max9485_driver_data *drvdata;
+};
+
+struct max9485_driver_data {
+ struct clk *xclk;
+ struct i2c_client *client;
+ u8 reg_value;
+ unsigned long clkout_rate;
+ struct regulator *supply;
+ struct gpio_desc *reset_gpio;
+ struct max9485_clk_hw hw[MAX9485_NUM_CLKS];
+
+ struct {
+ struct clk_hw_onecell_data data;
+ struct clk_hw *hw[MAX9485_NUM_CLKS];
+ } onecell;
+};
+
+static int max9485_update_bits(struct max9485_driver_data *drvdata,
+ u8 mask, u8 value)
+{
+ int ret;
+
+ drvdata->reg_value &= ~mask;
+ drvdata->reg_value |= value;
+
+ dev_dbg(&drvdata->client->dev,
+ "updating mask %02x value %02x -> %02x\n",
+ mask, value, drvdata->reg_value);
+
+ ret = i2c_master_send(drvdata->client,
+ &drvdata->reg_value,
+ sizeof(drvdata->reg_value));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int max9485_clk_prepare(struct clk_hw *hw)
+{
+ struct max9485_clk_hw *clk_hw =
+ container_of(hw, struct max9485_clk_hw, hw);
+
+ return max9485_update_bits(clk_hw->drvdata,
+ clk_hw->enable_bit,
+ clk_hw->enable_bit);
+}
+
+static void max9485_clk_unprepare(struct clk_hw *hw)
+{
+ struct max9485_clk_hw *clk_hw =
+ container_of(hw, struct max9485_clk_hw, hw);
+
+ max9485_update_bits(clk_hw->drvdata, clk_hw->enable_bit, 0);
+}
+
+/*
+ * MCLK OUT
+ */
+
+/* The MCLK output can only provide the same rate as the input clock */
+static unsigned long max9485_mclkout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return MAX9485_INPUT_FREQ;
+}
+
+/*
+ * CLKOUT - configurable clock output
+ */
+static int max9485_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ const struct max9485_rate *entry;
+ struct max9485_clk_hw *clk_hw =
+ container_of(hw, struct max9485_clk_hw, hw);
+
+ for (entry = max9485_rates; entry->out != 0; entry++)
+ if (entry->out == rate)
+ break;
+
+ if (entry->out == 0)
+ return -EINVAL;
+
+ clk_hw->drvdata->clkout_rate = rate;
+
+ return max9485_update_bits(clk_hw->drvdata,
+ MAX9485_FREQ_MASK,
+ entry->reg_value);
+}
+
+static long max9485_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ const struct max9485_rate *curr, *prev = NULL;
+
+ for (curr = max9485_rates; curr->out != 0; curr++) {
+ /* Exact matches */
+ if (curr->out == rate)
+ return rate;
+
+ /*
+ * Find the first entry that has a frequency higher than the
+ * requested one.
+ */
+ if (curr->out > rate) {
+ unsigned int mid;
+
+ /*
+ * If this is the first entry, clamp the value to the
+ * lowest possible frequency.
+ */
+ if (!prev)
+ return curr->out;
+
+ /*
+ * Otherwise, determine whether the previous entry or
+ * current one is closer.
+ */
+ mid = prev->out + ((curr->out - prev->out) / 2);
+
+ return (mid > rate) ? prev->out : curr->out;
+ }
+
+ prev = curr;
+ }
+
+ /* If the last entry was still too high, clamp the value */
+ return prev->out;
+}
+
+static unsigned long max9485_clkout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct max9485_clk_hw *clk_hw =
+ container_of(hw, struct max9485_clk_hw, hw);
+
+ return clk_hw->drvdata->clkout_rate;
+}
+
+struct max9485_clk {
+ const char *name;
+ int parent_index;
+ const struct clk_ops ops;
+ u8 enable_bit;
+};
+
+static const struct max9485_clk max9485_clks[MAX9485_NUM_CLKS] = {
+ [MAX9485_MCLKOUT] = {
+ .name = "mclkout",
+ .parent_index = -1,
+ .enable_bit = MAX9485_MCLK_ENABLE,
+ .ops = {
+ .prepare = max9485_clk_prepare,
+ .unprepare = max9485_clk_unprepare,
+ .recalc_rate = max9485_mclkout_recalc_rate,
+ },
+ },
+ [MAX9485_CLKOUT] = {
+ .name = "clkout",
+ .parent_index = -1,
+ .ops = {
+ .set_rate = max9485_clkout_set_rate,
+ .round_rate = max9485_clkout_round_rate,
+ .recalc_rate = max9485_clkout_recalc_rate,
+ },
+ },
+ [MAX9485_CLKOUT1] = {
+ .name = "clkout1",
+ .parent_index = MAX9485_CLKOUT,
+ .enable_bit = MAX9485_CLKOUT1_ENABLE,
+ .ops = {
+ .prepare = max9485_clk_prepare,
+ .unprepare = max9485_clk_unprepare,
+ .recalc_rate = max9485_clkout_recalc_rate,
+ },
+ },
+ [MAX9485_CLKOUT2] = {
+ .name = "clkout2",
+ .parent_index = MAX9485_CLKOUT,
+ .enable_bit = MAX9485_CLKOUT2_ENABLE,
+ .ops = {
+ .prepare = max9485_clk_prepare,
+ .unprepare = max9485_clk_unprepare,
+ .recalc_rate = max9485_clkout_recalc_rate,
+ },
+ },
+};
+
+static int max9485_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max9485_driver_data *drvdata;
+ struct device *dev = &client->dev;
+ unsigned long freq;
+ int i, ret;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (drvdata == NULL)
+ return -ENOMEM;
+
+ drvdata->xclk = devm_clk_get(dev, "xclk");
+ if (IS_ERR(drvdata->xclk))
+ return PTR_ERR(drvdata->xclk);
+
+ freq = clk_get_rate(drvdata->xclk);
+ if (freq != MAX9485_INPUT_FREQ) {
+ dev_err(dev, "Illegal xclk frequency of %ld\n", freq);
+ return -EINVAL;
+ }
+
+ drvdata->supply = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(drvdata->supply))
+ return PTR_ERR(drvdata->supply);
+
+ ret = regulator_enable(drvdata->supply);
+ if (ret < 0)
+ return ret;
+
+ drvdata->reset_gpio =
+ devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(drvdata->reset_gpio))
+ return PTR_ERR(drvdata->reset_gpio);
+
+ i2c_set_clientdata(client, drvdata);
+ drvdata->client = client;
+
+ for (i = 0; i < MAX9485_NUM_CLKS; i++) {
+ int parent_index = max9485_clks[i].parent_index;
+ const char *name;
+
+ if (of_property_read_string_index(dev->of_node,
+ "clock-output-names",
+ i, &name) == 0)
+ drvdata->hw[i].init.name = name;
+ else
+ drvdata->hw[i].init.name = max9485_clks[i].name;
+
+ drvdata->hw[i].init.ops = &max9485_clks[i].ops;
+ drvdata->hw[i].init.flags = CLK_IS_BASIC;
+
+ if (parent_index > 0) {
+ drvdata->hw[i].init.parent_names =
+ &drvdata->hw[parent_index].init.name;
+ drvdata->hw[i].init.num_parents = 1;
+ drvdata->hw[i].init.flags |= CLK_SET_RATE_PARENT;
+ }
+
+ drvdata->hw[i].enable_bit = max9485_clks[i].enable_bit;
+ drvdata->hw[i].hw.init = &drvdata->hw[i].init;
+ drvdata->hw[i].drvdata = drvdata;
+
+ ret = devm_clk_hw_register(dev, &drvdata->hw[i].hw);
+ if (ret < 0)
+ return ret;
+
+ drvdata->onecell.hw[i] = &drvdata->hw[i].hw;
+ }
+
+ drvdata->onecell.data.num = MAX9485_NUM_CLKS;
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ &drvdata->onecell.data);
+}
+
+static const struct of_device_id max9485_dt_ids[] = {
+ { .compatible = "maxim,max9485", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max9485_dt_ids);
+
+static const struct i2c_device_id max9485_i2c_ids[] = {
+ { .name = "max9485", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max9485_i2c_ids);
+
+static struct i2c_driver max9485_driver = {
+ .driver = {
+ .name = "max9485",
+ .of_match_table = max9485_dt_ids,
+ },
+ .probe = max9485_i2c_probe,
+ .id_table = max9485_i2c_ids,
+};
+module_i2c_driver(max9485_driver);
+
+MODULE_AUTHOR("Daniel Mack <daniel@zonque.org>");
+MODULE_DESCRIPTION("MAX9485 Programmable Audio Clock Generator");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/clock/maxim,max9485.h b/include/dt-bindings/clock/maxim,max9485.h
new file mode 100644
index 000000000000..23add67f32a7
--- /dev/null
+++ b/include/dt-bindings/clock/maxim,max9485.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Daniel Mack
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __DT_BINDINGS_MAX9485_CLK_H
+#define __DT_BINDINGS_MAX9485_CLK_H
+
+#define MAX9485_MCLKOUT 0
+#define MAX9485_CLKOUT 1
+#define MAX9485_CLKOUT1 2
+#define MAX9485_CLKOUT2 3
+
+#endif /* __DT_BINDINGS_MAX9485_CLK_H */
--
2.14.3
^ permalink raw reply related
* Re: [PATCH 2/2] slimbus: ngd: Add qcom SLIMBus NGD driver
From: Srinivas Kandagatla @ 2018-05-21 8:54 UTC (permalink / raw)
To: kbuild test robot
Cc: mark.rutland, devicetree, alsa-devel, girishm, bgoswami, gregkh,
broonie, linux-kernel, robh+dt, kramasub, kbuild-all,
linux-arm-msm, sdharia
In-Reply-To: <201805190351.kbyN0JPN%fengguang.wu@intel.com>
Thanks for the report!
This patch has dependency on https://lkml.org/lkml/2018/5/17/251
I should have mentioned this in cover letter!
thanks,
srini
On 18/05/18 22:39, kbuild test robot wrote:
> Hi Srinivas,
>
> I love your patch! Yet something to improve:
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on v4.17-rc5 next-20180517]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Srinivas-Kandagatla/slimbus-ngd-dt-bindings-Add-slim-ngd-dt-bindings/20180518-193916
> config: arm-allmodconfig (attached as .config)
> compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
> reproduce:
> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=arm
>
> All error/warnings (new ones prefixed by >>):
>
> drivers/slimbus/qcom-ngd-ctrl.c: In function 'qcom_slim_ngd_get_laddr':
>>> drivers/slimbus/qcom-ngd-ctrl.c:862:8: error: implicit declaration of function 'slim_prepare_txn'; did you mean 'slab_prepare_cpu'? [-Werror=implicit-function-declaration]
> ret = slim_prepare_txn(sctrl, &txn, &done, true);
> ^~~~~~~~~~~~~~~~
> slab_prepare_cpu
> drivers/slimbus/qcom-ngd-ctrl.c: In function 'qcom_slim_ngd_notify_slaves':
>>> drivers/slimbus/qcom-ngd-ctrl.c:969:11: error: implicit declaration of function 'of_slim_get_device'; did you mean 'slim_get_device'? [-Werror=implicit-function-declaration]
> sbdev = of_slim_get_device(&ctrl->ctrl, node);
> ^~~~~~~~~~~~~~~~~~
> slim_get_device
>>> drivers/slimbus/qcom-ngd-ctrl.c:969:9: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
> sbdev = of_slim_get_device(&ctrl->ctrl, node);
> ^
> cc1: some warnings being treated as errors
>
> vim +862 drivers/slimbus/qcom-ngd-ctrl.c
>
> 839
> 840 static int qcom_slim_ngd_get_laddr(struct slim_controller *sctrl,
> 841 struct slim_eaddr *ea, u8 *laddr)
> 842 {
> 843 DECLARE_COMPLETION_ONSTACK(done);
> 844 struct slim_val_inf msg = {0};
> 845 struct slim_msg_txn txn;
> 846 u8 wbuf[10] = {0};
> 847 u8 rbuf[10] = {0};
> 848 int ret;
> 849
> 850 txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
> 851 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
> 852 txn.la = SLIM_LA_MGR;
> 853 txn.ec = 0;
> 854
> 855 txn.mc = SLIM_USR_MC_ADDR_QUERY;
> 856 txn.rl = 11;
> 857 txn.msg = &msg;
> 858 txn.msg->num_bytes = 7;
> 859 txn.msg->wbuf = wbuf;
> 860 txn.msg->rbuf = rbuf;
> 861
> > 862 ret = slim_prepare_txn(sctrl, &txn, &done, true);
> 863 if (ret)
> 864 return ret;
> 865
> 866 wbuf[0] = (u8)txn.tid;
> 867 memcpy(&wbuf[1], ea, sizeof(*ea));
> 868 ret = slim_do_transfer(sctrl, &txn);
> 869
> 870 *laddr = rbuf[6];
> 871
> 872 return ret;
> 873 }
> 874
> 875 static int qcom_slim_ngd_exit_dma(struct qcom_slim_ngd_ctrl *ctrl)
> 876 {
> 877 if (ctrl->dma_rx_channel)
> 878 dma_release_channel(ctrl->dma_rx_channel);
> 879
> 880 if (ctrl->dma_tx_channel)
> 881 dma_release_channel(ctrl->dma_tx_channel);
> 882
> 883 ctrl->dma_tx_channel = ctrl->dma_rx_channel = NULL;
> 884
> 885 return 0;
> 886 }
> 887
> 888 static void qcom_slim_ngd_setup(struct qcom_slim_ngd_ctrl *ctrl)
> 889 {
> 890 u32 cfg = readl_relaxed(ctrl->base +
> 891 NGD_BASE(ctrl->id, ctrl->ver));
> 892
> 893 if (ctrl->state == QCOM_SLIM_NGD_CTRL_DOWN)
> 894 qcom_slim_ngd_init_dma(ctrl);
> 895
> 896 /* By default enable message queues */
> 897 cfg |= NGD_CFG_RX_MSGQ_EN;
> 898 cfg |= NGD_CFG_TX_MSGQ_EN;
> 899
> 900 /* Enable NGD if it's not already enabled*/
> 901 if (!(cfg & NGD_CFG_ENABLE))
> 902 cfg |= NGD_CFG_ENABLE;
> 903
> 904 writel_relaxed(cfg, ctrl->base + NGD_BASE(ctrl->id, ctrl->ver));
> 905 }
> 906
> 907 static int qcom_slim_ngd_power_up(struct qcom_slim_ngd_ctrl *ctrl)
> 908 {
> 909 enum qcom_slim_ngd_state cur_state = ctrl->state;
> 910 void __iomem *ngd;
> 911 u32 laddr, rx_msgq;
> 912 int timeout, ret = 0;
> 913
> 914 if (ctrl->state == QCOM_SLIM_NGD_CTRL_DOWN) {
> 915 timeout = wait_for_completion_timeout(&ctrl->qmi.qmi_comp, HZ);
> 916 if (!timeout)
> 917 return -EREMOTEIO;
> 918 }
> 919
> 920 if (ctrl->state == QCOM_SLIM_NGD_CTRL_ASLEEP ||
> 921 ctrl->state == QCOM_SLIM_NGD_CTRL_DOWN) {
> 922 ret = qcom_slim_qmi_power_request(ctrl, true);
> 923 if (ret) {
> 924 dev_err(ctrl->dev, "SLIM QMI power request failed:%d\n",
> 925 ret);
> 926 return ret;
> 927 }
> 928 }
> 929
> 930 ctrl->ver = readl_relaxed(ctrl->base);
> 931 /* Version info in 16 MSbits */
> 932 ctrl->ver >>= 16;
> 933 ngd = ctrl->base + NGD_BASE(ctrl->id, ctrl->ver);
> 934 laddr = readl_relaxed(ngd + NGD_STATUS);
> 935 if (laddr & NGD_LADDR) {
> 936 /*
> 937 * external MDM restart case where ADSP itself was active framer
> 938 * For example, modem restarted when playback was active
> 939 */
> 940 if (cur_state == QCOM_SLIM_NGD_CTRL_AWAKE) {
> 941 dev_info(ctrl->dev, "Subsys restart: ADSP active framer\n");
> 942 return 0;
> 943 }
> 944 return 0;
> 945 }
> 946
> 947 writel_relaxed(DEF_NGD_INT_MASK, ctrl->base + NGD_INT_EN +
> 948 NGD_BASE(ctrl->id, ctrl->ver));
> 949 rx_msgq = readl_relaxed(ngd + NGD_RX_MSGQ_CFG);
> 950
> 951 writel_relaxed(rx_msgq|SLIM_RX_MSGQ_TIMEOUT_VAL, ngd + NGD_RX_MSGQ_CFG);
> 952 qcom_slim_ngd_setup(ctrl);
> 953
> 954 timeout = wait_for_completion_timeout(&ctrl->reconf, HZ);
> 955 if (!timeout) {
> 956 dev_err(ctrl->dev, "capability exchange timed-out\n");
> 957 return -ETIMEDOUT;
> 958 }
> 959
> 960 return 0;
> 961 }
> 962
> 963 static void qcom_slim_ngd_notify_slaves(struct qcom_slim_ngd_ctrl *ctrl)
> 964 {
> 965 struct slim_device *sbdev;
> 966 struct device_node *node;
> 967
> 968 for_each_child_of_node(ctrl->dev->of_node, node) {
> > 969 sbdev = of_slim_get_device(&ctrl->ctrl, node);
> 970 if (!sbdev)
> 971 continue;
> 972
> 973 if (slim_get_logical_addr(sbdev))
> 974 dev_err(ctrl->dev, "Failed to get logical address\n");
> 975 }
> 976 }
> 977
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation
>
^ permalink raw reply
* Re: [PATCH 1/2] slimbus: ngd: dt-bindings: Add slim ngd dt bindings
From: Srinivas Kandagatla @ 2018-05-21 8:49 UTC (permalink / raw)
To: Trilok Soni, gregkh, robh+dt
Cc: mark.rutland, devicetree, alsa-devel, girishm, linux-arm-msm,
broonie, linux-kernel, bgoswami, kramasub, sdharia
In-Reply-To: <802138cc-77cc-9800-f725-0ab8a9f0467e@codeaurora.org>
On 18/05/18 21:47, Trilok Soni wrote:
> Hi Srinivas
>
> On 5/16/2018 9:51 AM, Srinivas Kandagatla wrote:
>> This patch adds bindings for Qualcomm SLIMBus NGD controller found in
>> all new SoCs starting from B family.
>
> "X/Y/Z family" has no meaning here in upstream and just put the
> processor name from which you are adding the support or tested to start
> with.
Thanks, Will update this when I send new version of this patch.
thanks,
srini
>
>
^ permalink raw reply
* Re: [PATCH V2 2/3] clk: imx7d: correct enet clock CCGR registers
From: Stefan Agner @ 2018-05-21 8:14 UTC (permalink / raw)
To: Anson Huang
Cc: shawnguo, kernel, Fabio Estevam, robh+dt, mark.rutland,
mturquette, sboyd, Adriana Reus, rui.silva, dl-linux-imx,
linux-arm-kernel, devicetree, linux-kernel, linux-clk
In-Reply-To: <AM3PR04MB1315417C51882B554AEBC617F5950@AM3PR04MB1315.eurprd04.prod.outlook.com>
On 21.05.2018 04:35, Anson Huang wrote:
> Hi, Stefan
>
> Anson Huang
> Best Regards!
>
>
>> -----Original Message-----
>> From: Stefan Agner [mailto:stefan@agner.ch]
>> Sent: Friday, May 18, 2018 9:02 PM
>> To: Anson Huang <anson.huang@nxp.com>
>> Cc: shawnguo@kernel.org; kernel@pengutronix.de; Fabio Estevam
>> <fabio.estevam@nxp.com>; robh+dt@kernel.org; mark.rutland@arm.com;
>> mturquette@baylibre.com; sboyd@kernel.org; Adriana Reus
>> <adriana.reus@nxp.com>; rui.silva@linaro.org; dl-linux-imx
>> <linux-imx@nxp.com>; linux-arm-kernel@lists.infradead.org;
>> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
>> linux-clk@vger.kernel.org
>> Subject: Re: [PATCH V2 2/3] clk: imx7d: correct enet clock CCGR registers
>>
>> On 18.05.2018 03:01, Anson Huang wrote:
>> > Correct enet clock gates as below:
>> >
>> > CCGR6: IMX7D_ENET_AXI_ROOT_CLK (enet1 and enet2 bus clocks)
>> > CCGR112: IMX7D_ENET1_TIME_ROOT_CLK, IMX7D_ENET1_IPG_ROOT_CLK
>> > CCGR113: IMX7D_ENET2_TIME_ROOT_CLK, IMX7D_ENET2_IPG_ROOT_CLK
>> >
>> > Just rename unused IMX7D_ENETx_REF_ROOT_CLK for
>> > IMX7D_ENETx_IPG_ROOT_CLK instead of adding new clocks.
>>
>> Are you sure that IMX7D_ENETx_REF_ROOT_CLK are not used?
>>
>> I understand that the reference manual does not a gate at 0x44e0...
>>
>> But in a earlier revision of our Colibri iMX7 we actually used clock out, and
>> referenced this clock to enable the reference clock (see also:
>> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatch
>> work.kernel.org%2Fpatch%2F9211371%2F&data=02%7C01%7CAnson.Huang%
>> 40nxp.com%7Cea0856a68d8e4b921ba608d5bcbf9c02%7C686ea1d3bc2b4c6fa
>> 92cd99c5c301635%7C0%7C1%7C636622453508888330&sdata=rEhwj0innLDc
>> AEgxJyqd5vtG3SNVS05r2hEFvSc%2BQQs%3D&reserved=0).
>>
>> I guess if the gate really does not exist, then we should/would have to set
>> IMX7D_ENET1_REF_ROOT_DIV to use the SoC provided ref clock.
>>
>> --
>> Stefan
>
> I looked into the RTL and also checked with our design team, they confirm that
> there is no CCGR78(0x44e0) and CCGR80(0x4500) on i.MX7D, the register offset
> are there, but no hardware wire connection for them. That is why they did NOT
> list them in Reference Manual. So I think we can remove them.
>
> For your case of using them as clock input, maybe clock tree auto use its parent
> IMX7D_ENETx_REF_ROOT_DIV which is existing, so it works.
That make sense.
The change looks good to me.
Reviewed-by: Stefan Agner <stefan@agner.ch>
--
Stefan
>
> Anson.
>
>>
>> >
>> > Based on Andy Duan's patch from the NXP kernel tree.
>> >
>> > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
>> > ---
>> > drivers/clk/imx/clk-imx7d.c | 10 ++++++----
>> > include/dt-bindings/clock/imx7d-clock.h | 4 ++--
>> > 2 files changed, 8 insertions(+), 6 deletions(-)
>> >
>> > diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
>> > index 23d5090a..d4936b9 100644
>> > --- a/drivers/clk/imx/clk-imx7d.c
>> > +++ b/drivers/clk/imx/clk-imx7d.c
>> > @@ -26,6 +26,8 @@ static u32 share_count_sai1; static u32
>> > share_count_sai2; static u32 share_count_sai3; static u32
>> > share_count_nand;
>> > +static u32 share_count_enet1;
>> > +static u32 share_count_enet2;
>> >
>> > static const struct clk_div_table test_div_table[] = {
>> > { .val = 3, .div = 1, },
>> > @@ -805,6 +807,10 @@ static void __init imx7d_clocks_init(struct
>> > device_node *ccm_node)
>> > clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate4("mipi_dsi_root_clk",
>> > "mipi_dsi_post_div", base + 0x4650, 0);
>> > clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate4("mipi_csi_root_clk",
>> > "mipi_csi_post_div", base + 0x4640, 0);
>> > clks[IMX7D_MIPI_DPHY_ROOT_CLK] =
>> imx_clk_gate4("mipi_dphy_root_clk",
>> > "mipi_dphy_post_div", base + 0x4660, 0);
>> > + clks[IMX7D_ENET1_IPG_ROOT_CLK] =
>> > imx_clk_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base
>> > + 0x4700, 0, &share_count_enet1);
>> > + clks[IMX7D_ENET1_TIME_ROOT_CLK] =
>> > imx_clk_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div",
>> > base + 0x4700, 0, &share_count_enet1);
>> > + clks[IMX7D_ENET2_IPG_ROOT_CLK] =
>> > imx_clk_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base
>> > + 0x4710, 0, &share_count_enet2);
>> > + clks[IMX7D_ENET2_TIME_ROOT_CLK] =
>> > imx_clk_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div",
>> > base + 0x4710, 0, &share_count_enet2);
>> > clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2_shared2("sai1_root_clk",
>> > "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
>> > clks[IMX7D_SAI1_IPG_CLK] = imx_clk_gate2_shared2("sai1_ipg_clk",
>> > "ipg_root_clk", base + 0x48c0, 0, &share_count_sai1);
>> > clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2_shared2("sai2_root_clk",
>> > "sai2_post_div", base + 0x48d0, 0, &share_count_sai2); @@ -812,10
>> > +818,6 @@ static void __init imx7d_clocks_init(struct device_node
>> > *ccm_node)
>> > clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2_shared2("sai3_root_clk",
>> > "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
>> > clks[IMX7D_SAI3_IPG_CLK] = imx_clk_gate2_shared2("sai3_ipg_clk",
>> > "ipg_root_clk", base + 0x48e0, 0, &share_count_sai3);
>> > clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate4("spdif_root_clk",
>> > "spdif_post_div", base + 0x44d0, 0);
>> > - clks[IMX7D_ENET1_REF_ROOT_CLK] =
>> imx_clk_gate4("enet1_ref_root_clk",
>> > "enet1_ref_post_div", base + 0x44e0, 0);
>> > - clks[IMX7D_ENET1_TIME_ROOT_CLK] =
>> > imx_clk_gate4("enet1_time_root_clk", "enet1_time_post_div", base +
>> > 0x44f0, 0);
>> > - clks[IMX7D_ENET2_REF_ROOT_CLK] =
>> imx_clk_gate4("enet2_ref_root_clk",
>> > "enet2_ref_post_div", base + 0x4500, 0);
>> > - clks[IMX7D_ENET2_TIME_ROOT_CLK] =
>> > imx_clk_gate4("enet2_time_root_clk", "enet2_time_post_div", base +
>> > 0x4510, 0);
>> > clks[IMX7D_EIM_ROOT_CLK] = imx_clk_gate4("eim_root_clk",
>> > "eim_post_div", base + 0x4160, 0);
>> > clks[IMX7D_NAND_RAWNAND_CLK] =
>> > imx_clk_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base +
>> > 0x4140, 0, &share_count_nand);
>> > clks[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] =
>> > imx_clk_gate2_shared2("nand_usdhc_rawnand_clk",
>> "nand_usdhc_root_clk",
>> > base + 0x4140, 0, &share_count_nand); diff --git
>> > a/include/dt-bindings/clock/imx7d-clock.h
>> > b/include/dt-bindings/clock/imx7d-clock.h
>> > index b2325d3e2..0d67f53 100644
>> > --- a/include/dt-bindings/clock/imx7d-clock.h
>> > +++ b/include/dt-bindings/clock/imx7d-clock.h
>> > @@ -168,7 +168,7 @@
>> > #define IMX7D_SPDIF_ROOT_SRC 155
>> > #define IMX7D_SPDIF_ROOT_CG 156
>> > #define IMX7D_SPDIF_ROOT_DIV 157
>> > -#define IMX7D_ENET1_REF_ROOT_CLK 158
>> > +#define IMX7D_ENET1_IPG_ROOT_CLK 158
>> > #define IMX7D_ENET1_REF_ROOT_SRC 159
>> > #define IMX7D_ENET1_REF_ROOT_CG 160
>> > #define IMX7D_ENET1_REF_ROOT_DIV 161
>> > @@ -176,7 +176,7 @@
>> > #define IMX7D_ENET1_TIME_ROOT_SRC 163
>> > #define IMX7D_ENET1_TIME_ROOT_CG 164
>> > #define IMX7D_ENET1_TIME_ROOT_DIV 165
>> > -#define IMX7D_ENET2_REF_ROOT_CLK 166
>> > +#define IMX7D_ENET2_IPG_ROOT_CLK 166
>> > #define IMX7D_ENET2_REF_ROOT_SRC 167
>> > #define IMX7D_ENET2_REF_ROOT_CG 168
>> > #define IMX7D_ENET2_REF_ROOT_DIV 169
^ permalink raw reply
* Re: [PATCH 12/15] drm/sun4i: Add support for second clock parent to DW HDMI PHY clk driver
From: Maxime Ripard @ 2018-05-21 8:12 UTC (permalink / raw)
To: Jernej Skrabec
Cc: wens-jdAy2FN1RRM, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20180519183127.2718-13-jernej.skrabec-gGgVlfcn5nU@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 3702 bytes --]
On Sat, May 19, 2018 at 08:31:24PM +0200, Jernej Skrabec wrote:
> Expand HDMI PHY clock driver to support second clock parent.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec-gGgVlfcn5nU@public.gmane.org>
> ---
> drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 6 +-
> drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 29 ++++++-
> drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 90 ++++++++++++++++------
> 3 files changed, 98 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> index 801a17222762..aadbe0a10b0c 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> @@ -98,7 +98,8 @@
> #define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN BIT(29)
> #define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28)
> #define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27)
> -#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL BIT(26)
> +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK BIT(26)
> +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26
> #define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25)
> #define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22)
> #define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20)
> @@ -190,6 +191,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
> void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
> const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
>
> -int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev);
> +int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
> + bool second_parent);
>
> #endif /* _SUN8I_DW_HDMI_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> index deba47ed69d8..7a911f0a3ae3 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> @@ -183,7 +183,13 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi,
> regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
> SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
>
> - regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init);
> + /*
> + * NOTE: We have to be careful not to overwrite PHY parent
> + * clock selection bit and clock divider.
> + */
> + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
> + ~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
> + pll_cfg1_init);
It feels like it belongs in a separate patch.
> regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
> (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
> pll_cfg2_init);
> @@ -352,6 +358,10 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
> SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
> SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
>
> + /* reset PLL clock configuration */
> + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
> + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, 0);
> +
Ditto,
> +
> + /*
> + * Even though HDMI PHY clock doesn't have enable/disable
> + * handlers, we have to enable it. Otherwise it could happen
> + * that parent PLL is not enabled by clock framework in a
> + * highly unlikely event when parent PLL is used solely for
> + * HDMI PHY clock.
> + */
> + clk_prepare_enable(phy->clk_phy);
The implementation of the clock doesn't really matter in our API
usage. If we're using a clock, we have to call
clk_prepare_enable. That's documented everywhere, and mentionning how
the clock is implemented is an abstraction leakage and it's
irrelevant. I'd simply remove the comment here.
And it should be in a separate patch as well.
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH] dt-bindings: soc: update MT6797 power domain
From: KaiChieh Chuang @ 2018-05-21 8:09 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
wsd_upstream-NuS5LvNUpcJWk0Htik3J/w,
mars.cheng-NuS5LvNUpcJWk0Htik3J/w,
matthias.bgg-Re5JQEeQqe8AvxtiuMwx3w,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
kaichieh.chuang-NuS5LvNUpcJWk0Htik3J/w
remove unused power domain in mt6797 and re-index
Signed-off-by: KaiChieh Chuang <kaichieh.chuang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Reviewed-by: Mars Cheng <mars.cheng-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
include/dt-bindings/power/mt6797-power.h | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/include/dt-bindings/power/mt6797-power.h b/include/dt-bindings/power/mt6797-power.h
index a60c1d8..f96c4e2 100644
--- a/include/dt-bindings/power/mt6797-power.h
+++ b/include/dt-bindings/power/mt6797-power.h
@@ -20,11 +20,6 @@
#define MT6797_POWER_DOMAIN_MM 3
#define MT6797_POWER_DOMAIN_AUDIO 4
#define MT6797_POWER_DOMAIN_MFG_ASYNC 5
-#define MT6797_POWER_DOMAIN_MFG 6
-#define MT6797_POWER_DOMAIN_MFG_CORE0 7
-#define MT6797_POWER_DOMAIN_MFG_CORE1 8
-#define MT6797_POWER_DOMAIN_MFG_CORE2 9
-#define MT6797_POWER_DOMAIN_MFG_CORE3 10
-#define MT6797_POWER_DOMAIN_MJC 11
+#define MT6797_POWER_DOMAIN_MJC 6
#endif /* _DT_BINDINGS_POWER_MT6797_POWER_H */
--
1.9.1
^ permalink raw reply related
* Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top
From: Maxime Ripard @ 2018-05-21 8:07 UTC (permalink / raw)
To: Jernej Skrabec
Cc: mark.rutland, devicetree, linux-sunxi, linux-kernel, dri-devel,
wens, robh+dt, linux-clk, linux-arm-kernel
In-Reply-To: <20180519183127.2718-7-jernej.skrabec@siol.net>
[-- Attachment #1.1: Type: text/plain, Size: 2626 bytes --]
On Sat, May 19, 2018 at 08:31:18PM +0200, Jernej Skrabec wrote:
> If SoC has TCON TOP unit, it has to be configured from TCON, since it
> has all information needed. Additionally, if it is TCON TV, it must also
> enable bus gate inside TCON TOP unit.
Why?
> Add support for such TCONs.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
> drivers/gpu/drm/sun4i/sun4i_tcon.c | 28 ++++++++++++++++++++++++++++
> drivers/gpu/drm/sun4i/sun4i_tcon.h | 8 ++++++++
> 2 files changed, 36 insertions(+)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index 08747fc3ee71..e0c562ce1c22 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -688,6 +688,16 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> dev_err(dev, "Couldn't get the TCON bus clock\n");
> return PTR_ERR(tcon->clk);
> }
> +
> + if (tcon->quirks->needs_tcon_top && tcon->quirks->has_channel_1) {
> + tcon->top_clk = devm_clk_get(dev, "tcon-top");
> + if (IS_ERR(tcon->top_clk)) {
> + dev_err(dev, "Couldn't get the TCON TOP bus clock\n");
> + return PTR_ERR(tcon->top_clk);
> + }
> + clk_prepare_enable(tcon->top_clk);
> + }
> +
> clk_prepare_enable(tcon->clk);
>
> if (tcon->quirks->has_channel_0) {
> @@ -712,6 +722,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
> {
> clk_disable_unprepare(tcon->clk);
> + clk_disable_unprepare(tcon->top_clk);
> }
>
> static int sun4i_tcon_init_irq(struct device *dev,
> @@ -980,6 +991,23 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
> tcon->id = engine->id;
> tcon->quirks = of_device_get_match_data(dev);
>
> + if (tcon->quirks->needs_tcon_top) {
> + struct device_node *np;
> +
> + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top", 0);
> + if (np) {
> + struct platform_device *pdev;
> +
> + pdev = of_find_device_by_node(np);
> + if (pdev)
> + tcon->tcon_top = platform_get_drvdata(pdev);
> + of_node_put(np);
> +
> + if (!tcon->tcon_top)
> + return -EPROBE_DEFER;
> + }
> + }
> +
I might have missed it, but I've not seen the bindings additions for
that property. This shouldn't really be done that way anyway, instead
of using a direct phandle, you should be using the of-graph, with the
TCON-top sitting where it belongs in the flow of data.
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: Type: text/plain, Size: 160 bytes --]
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* [PATCH V3 8/8] dt-bindings: stm32: add compatible for syscon
From: Christophe Roullier @ 2018-05-21 8:07 UTC (permalink / raw)
To: mark.rutland, mcoquelin.stm32, alexandre.torgue, peppe.cavallaro
Cc: devicetree, linux-arm-kernel, netdev, christophe.roullier, andrew
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>
This patch describes syscon DT bindings.
Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
Documentation/devicetree/bindings/arm/stm32.txt | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/stm32.txt b/Documentation/devicetree/bindings/arm/stm32.txt
index 6808ed9..e46ebad 100644
--- a/Documentation/devicetree/bindings/arm/stm32.txt
+++ b/Documentation/devicetree/bindings/arm/stm32.txt
@@ -8,3 +8,8 @@ using one of the following compatible strings:
st,stm32f746
st,stm32h743
st,stm32mp157
+
+Required nodes:
+- syscon: the soc bus node must have a system controller node pointing to the
+ global control registers, with the compatible string
+ "st,stm32mp157-syscfg", "syscon";
--
1.9.1
^ permalink raw reply related
* [PATCH V3 7/8] ARM: dts: stm32: add support of ethernet on stm32mp157c-ev1
From: Christophe Roullier @ 2018-05-21 8:07 UTC (permalink / raw)
To: mark.rutland, mcoquelin.stm32, alexandre.torgue, peppe.cavallaro
Cc: devicetree, linux-arm-kernel, netdev, christophe.roullier, andrew
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>
MAC is connected to a PHY in RGMII mode.
Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
arch/arm/boot/dts/stm32mp157c-ev1.dts | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts
index 57e6dbc..a7fee5c 100644
--- a/arch/arm/boot/dts/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts
@@ -17,5 +17,25 @@
aliases {
serial0 = &uart4;
+ ethernet0 = ðernet0;
+ };
+};
+
+ðernet0 {
+ status = "okay";
+ pinctrl-0 = <ðernet0_rgmii_pins_a>;
+ pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>;
+ pinctrl-names = "default", "sleep";
+ phy-mode = "rgmii";
+ max-speed = <1000>;
+ phy-handle = <&phy0>;
+
+ mdio0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dwmac-mdio";
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ };
};
};
--
1.9.1
^ permalink raw reply related
* [PATCH V3 6/8] net: stmmac: add dwmac-4.20a compatible
From: Christophe Roullier @ 2018-05-21 8:07 UTC (permalink / raw)
To: mark.rutland, mcoquelin.stm32, alexandre.torgue, peppe.cavallaro
Cc: devicetree, linux-arm-kernel, netdev, christophe.roullier, andrew
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>
Manage dwmac-4.20a version from synopsys
Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index ebd3e5f..6d141f3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -472,7 +472,8 @@ struct plat_stmmacenet_data *
}
if (of_device_is_compatible(np, "snps,dwmac-4.00") ||
- of_device_is_compatible(np, "snps,dwmac-4.10a")) {
+ of_device_is_compatible(np, "snps,dwmac-4.10a") ||
+ of_device_is_compatible(np, "snps,dwmac-4.20a")) {
plat->has_gmac4 = 1;
plat->has_gmac = 0;
plat->pmt = 1;
--
1.9.1
^ permalink raw reply related
* [PATCH V3 5/8] ARM: dts: stm32: Add ethernet dwmac on stm32mp1
From: Christophe Roullier @ 2018-05-21 8:07 UTC (permalink / raw)
To: mark.rutland, mcoquelin.stm32, alexandre.torgue, peppe.cavallaro
Cc: devicetree, linux-arm-kernel, netdev, christophe.roullier, andrew
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>
Add Ethernet support (Synopsys MAC IP 4.20a) on stm32mp1 SOC.
Enable feature supported by the stmmac driver, such as TSO.
Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
arch/arm/boot/dts/stm32mp157c.dtsi | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index dbc0e707..99cc94c 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -179,5 +179,35 @@
clocks = <&rcc USART1_K>;
status = "disabled";
};
+
+ stmmac_axi_config_0: stmmac-axi-config {
+ snps,wr_osr_lmt = <0x7>;
+ snps,rd_osr_lmt = <0x7>;
+ snps,blen = <0 0 0 0 16 8 4>;
+ };
+
+ ethernet0: ethernet@5800a000 {
+ compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";
+ reg = <0x5800a000 0x2000>;
+ reg-names = "stmmaceth";
+ interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_NONE>;
+ interrupt-names = "macirq";
+ clock-names = "stmmaceth",
+ "mac-clk-tx",
+ "mac-clk-rx",
+ "ethstp",
+ "syscfg-clk";
+ clocks = <&rcc ETHMAC>,
+ <&rcc ETHTX>,
+ <&rcc ETHRX>,
+ <&rcc ETHSTP>,
+ <&rcc SYSCFG>;
+ st,syscon = <&syscfg 0x4>;
+ snps,mixed-burst;
+ snps,pbl = <2>;
+ snps,axi-config = <&stmmac_axi_config_0>;
+ snps,tso;
+ status = "disabled";
+ };
};
};
--
1.9.1
^ permalink raw reply related
* [PATCH V3 4/8] ARM: dts: stm32: Add syscfg on stm32mp1
From: Christophe Roullier @ 2018-05-21 8:07 UTC (permalink / raw)
To: mark.rutland, mcoquelin.stm32, alexandre.torgue, peppe.cavallaro
Cc: devicetree, linux-arm-kernel, netdev, christophe.roullier, andrew
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>
System configuration controller is mainly used to manage
the compensation cell and other IOs and system related
settings.
Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
arch/arm/boot/dts/stm32mp157c.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index bc3eddc..dbc0e707 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -167,6 +167,11 @@
#reset-cells = <1>;
};
+ syscfg: system-config@50020000 {
+ compatible = "st,stm32mp157-syscfg", "syscon";
+ reg = <0x50020000 0x400>;
+ };
+
usart1: serial@5c000000 {
compatible = "st,stm32h7-uart";
reg = <0x5c000000 0x400>;
--
1.9.1
^ permalink raw reply related
* [PATCH V3 3/8] ARM: dts: stm32: add ethernet pins to stm32mp157c
From: Christophe Roullier @ 2018-05-21 8:07 UTC (permalink / raw)
To: mark.rutland, mcoquelin.stm32, alexandre.torgue, peppe.cavallaro
Cc: devicetree, andrew, christophe.roullier, linux-arm-kernel, netdev
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>
Add ethernet pins on stm32mp157c.
Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 46 +++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 6f044100..cf83eb244 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -158,6 +158,52 @@
bias-disable;
};
};
+
+ ethernet0_rgmii_pins_a: rgmii-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('G', 5, AF11)>, /* ETH_RGMII_CLK125 */
+ <STM32_PINMUX('G', 4, AF11)>, /* ETH_RGMII_GTX_CLK */
+ <STM32_PINMUX('G', 13, AF11)>, /* ETH_RGMII_TXD0 */
+ <STM32_PINMUX('G', 14, AF11)>, /* ETH_RGMII_TXD1 */
+ <STM32_PINMUX('C', 2, AF11)>, /* ETH_RGMII_TXD2 */
+ <STM32_PINMUX('E', 2, AF11)>, /* ETH_RGMII_TXD3 */
+ <STM32_PINMUX('B', 11, AF11)>, /* ETH_RGMII_TX_CTL */
+ <STM32_PINMUX('A', 2, AF11)>, /* ETH_MDIO */
+ <STM32_PINMUX('C', 1, AF11)>; /* ETH_MDC */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <3>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('C', 4, AF11)>, /* ETH_RGMII_RXD0 */
+ <STM32_PINMUX('C', 5, AF11)>, /* ETH_RGMII_RXD1 */
+ <STM32_PINMUX('B', 0, AF11)>, /* ETH_RGMII_RXD2 */
+ <STM32_PINMUX('B', 1, AF11)>, /* ETH_RGMII_RXD3 */
+ <STM32_PINMUX('A', 1, AF11)>, /* ETH_RGMII_RX_CLK */
+ <STM32_PINMUX('A', 7, AF11)>; /* ETH_RGMII_RX_CTL */
+ bias-disable;
+ };
+ };
+
+ ethernet0_rgmii_pins_sleep_a: rgmii-sleep-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('G', 5, ANALOG)>, /* ETH_RGMII_CLK125 */
+ <STM32_PINMUX('G', 4, ANALOG)>, /* ETH_RGMII_GTX_CLK */
+ <STM32_PINMUX('G', 13, ANALOG)>, /* ETH_RGMII_TXD0 */
+ <STM32_PINMUX('G', 14, ANALOG)>, /* ETH_RGMII_TXD1 */
+ <STM32_PINMUX('C', 2, ANALOG)>, /* ETH_RGMII_TXD2 */
+ <STM32_PINMUX('E', 2, ANALOG)>, /* ETH_RGMII_TXD3 */
+ <STM32_PINMUX('B', 11, ANALOG)>, /* ETH_RGMII_TX_CTL */
+ <STM32_PINMUX('A', 2, ANALOG)>, /* ETH_MDIO */
+ <STM32_PINMUX('C', 1, ANALOG)>, /* ETH_MDC */
+ <STM32_PINMUX('C', 4, ANALOG)>, /* ETH_RGMII_RXD0 */
+ <STM32_PINMUX('C', 5, ANALOG)>, /* ETH_RGMII_RXD1 */
+ <STM32_PINMUX('B', 0, ANALOG)>, /* ETH_RGMII_RXD2 */
+ <STM32_PINMUX('B', 1, ANALOG)>, /* ETH_RGMII_RXD3 */
+ <STM32_PINMUX('A', 1, ANALOG)>, /* ETH_RGMII_RX_CLK */
+ <STM32_PINMUX('A', 7, ANALOG)>; /* ETH_RGMII_RX_CTL */
+ };
+ };
};
pinctrl_z: pin-controller-z {
--
1.9.1
^ permalink raw reply related
* [PATCH V3 2/8] dt-bindings: stm32-dwmac: add support of MPU families
From: Christophe Roullier @ 2018-05-21 8:07 UTC (permalink / raw)
To: mark.rutland, mcoquelin.stm32, alexandre.torgue, peppe.cavallaro
Cc: devicetree, linux-arm-kernel, netdev, christophe.roullier, andrew
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>
Add description for Ethernet MPU families fields
Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/net/stm32-dwmac.txt | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/stm32-dwmac.txt b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
index 489dbcb..1341012 100644
--- a/Documentation/devicetree/bindings/net/stm32-dwmac.txt
+++ b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
@@ -6,14 +6,28 @@ Please see stmmac.txt for the other unchanged properties.
The device node has following properties.
Required properties:
-- compatible: Should be "st,stm32-dwmac" to select glue, and
+- compatible: For MCU family should be "st,stm32-dwmac" to select glue, and
"snps,dwmac-3.50a" to select IP version.
+ For MPU family should be "st,stm32mp1-dwmac" to select
+ glue, and "snps,dwmac-4.20a" to select IP version.
- clocks: Must contain a phandle for each entry in clock-names.
- clock-names: Should be "stmmaceth" for the host clock.
Should be "mac-clk-tx" for the MAC TX clock.
Should be "mac-clk-rx" for the MAC RX clock.
+ For MPU family need to add also "ethstp" for power mode clock and,
+ "syscfg-clk" for SYSCFG clock.
+- interrupt-names: Should contain a list of interrupt names corresponding to
+ the interrupts in the interrupts property, if available.
+ Should be "macirq" for the main MAC IRQ
+ Should be "eth_wake_irq" for the IT which wake up system
- st,syscon : Should be phandle/offset pair. The phandle to the syscon node which
- encompases the glue register, and the offset of the control register.
+ encompases the glue register, and the offset of the control register.
+
+Optional properties:
+- clock-names: For MPU family "mac-clk-ck" for PHY without quartz
+- st,int-phyclk (boolean) : valid only where PHY do not have quartz and need to be clock
+ by RCC
+
Example:
ethernet@40028000 {
--
1.9.1
^ permalink raw reply related
* [PATCH V3 1/8] net: ethernet: stmmac: add adaptation for stm32mp157c.
From: Christophe Roullier @ 2018-05-21 8:07 UTC (permalink / raw)
To: mark.rutland, mcoquelin.stm32, alexandre.torgue, peppe.cavallaro
Cc: devicetree, linux-arm-kernel, netdev, christophe.roullier, andrew
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>
Glue codes to support stm32mp157c device and stay
compatible with stm32 mcu family
Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 270 ++++++++++++++++++++--
1 file changed, 255 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
index 9e6db16..f51e327 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -16,49 +16,183 @@
#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/stmmac.h>
#include "stmmac_platform.h"
-#define MII_PHY_SEL_MASK BIT(23)
+#define SYSCFG_MCU_ETH_MASK BIT(23)
+#define SYSCFG_MP1_ETH_MASK GENMASK(23, 16)
+
+#define SYSCFG_PMCR_ETH_CLK_SEL BIT(16)
+#define SYSCFG_PMCR_ETH_REF_CLK_SEL BIT(17)
+#define SYSCFG_PMCR_ETH_SEL_MII BIT(20)
+#define SYSCFG_PMCR_ETH_SEL_RGMII BIT(21)
+#define SYSCFG_PMCR_ETH_SEL_RMII BIT(23)
+#define SYSCFG_PMCR_ETH_SEL_GMII 0
+#define SYSCFG_MCU_ETH_SEL_MII 0
+#define SYSCFG_MCU_ETH_SEL_RMII 1
struct stm32_dwmac {
struct clk *clk_tx;
struct clk *clk_rx;
+ struct clk *clk_eth_ck;
+ struct clk *clk_ethstp;
+ struct clk *syscfg_clk;
+ bool int_phyclk; /* Clock from RCC to drive PHY */
u32 mode_reg; /* MAC glue-logic mode register */
struct regmap *regmap;
u32 speed;
+ const struct stm32_ops *ops;
+ struct device *dev;
+};
+
+struct stm32_ops {
+ int (*set_mode)(struct plat_stmmacenet_data *plat_dat);
+ int (*clk_prepare)(struct stm32_dwmac *dwmac, bool prepare);
+ int (*suspend)(struct stm32_dwmac *dwmac);
+ void (*resume)(struct stm32_dwmac *dwmac);
+ int (*parse_data)(struct stm32_dwmac *dwmac,
+ struct device *dev);
+ u32 syscfg_eth_mask;
};
static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat)
{
struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
- u32 reg = dwmac->mode_reg;
- u32 val;
int ret;
- val = (plat_dat->interface == PHY_INTERFACE_MODE_MII) ? 0 : 1;
- ret = regmap_update_bits(dwmac->regmap, reg, MII_PHY_SEL_MASK, val);
- if (ret)
- return ret;
+ if (dwmac->ops->set_mode) {
+ ret = dwmac->ops->set_mode(plat_dat);
+ if (ret)
+ return ret;
+ }
ret = clk_prepare_enable(dwmac->clk_tx);
if (ret)
return ret;
- ret = clk_prepare_enable(dwmac->clk_rx);
- if (ret)
- clk_disable_unprepare(dwmac->clk_tx);
+ if (!dwmac->dev->power.is_suspended) {
+ ret = clk_prepare_enable(dwmac->clk_rx);
+ if (ret) {
+ clk_disable_unprepare(dwmac->clk_tx);
+ return ret;
+ }
+ }
+
+ if (dwmac->ops->clk_prepare) {
+ ret = dwmac->ops->clk_prepare(dwmac, true);
+ if (ret) {
+ clk_disable_unprepare(dwmac->clk_rx);
+ clk_disable_unprepare(dwmac->clk_tx);
+ }
+ }
return ret;
}
+static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare)
+{
+ int ret = 0;
+
+ if (prepare) {
+ ret = clk_prepare_enable(dwmac->syscfg_clk);
+ if (ret)
+ return ret;
+
+ if (dwmac->int_phyclk) {
+ ret = clk_prepare_enable(dwmac->clk_eth_ck);
+ if (ret) {
+ clk_disable_unprepare(dwmac->syscfg_clk);
+ return ret;
+ }
+ }
+ } else {
+ clk_disable_unprepare(dwmac->syscfg_clk);
+ if (dwmac->int_phyclk)
+ clk_disable_unprepare(dwmac->clk_eth_ck);
+ }
+ return ret;
+}
+
+static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
+{
+ struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
+ u32 reg = dwmac->mode_reg;
+ int val;
+
+ switch (plat_dat->interface) {
+ case PHY_INTERFACE_MODE_MII:
+ val = SYSCFG_PMCR_ETH_SEL_MII;
+ pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
+ break;
+ case PHY_INTERFACE_MODE_GMII:
+ val = SYSCFG_PMCR_ETH_SEL_GMII;
+ if (dwmac->int_phyclk)
+ val |= SYSCFG_PMCR_ETH_CLK_SEL;
+ pr_debug("SYSCFG init : PHY_INTERFACE_MODE_GMII\n");
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ val = SYSCFG_PMCR_ETH_SEL_RMII;
+ if (dwmac->int_phyclk)
+ val |= SYSCFG_PMCR_ETH_REF_CLK_SEL;
+ pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ val = SYSCFG_PMCR_ETH_SEL_RGMII;
+ if (dwmac->int_phyclk)
+ val |= SYSCFG_PMCR_ETH_CLK_SEL;
+ pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RGMII\n");
+ break;
+ default:
+ pr_debug("SYSCFG init : Do not manage %d interface\n",
+ plat_dat->interface);
+ /* Do not manage others interfaces */
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(dwmac->regmap, reg,
+ dwmac->ops->syscfg_eth_mask, val);
+}
+
+static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat)
+{
+ struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
+ u32 reg = dwmac->mode_reg;
+ int val;
+
+ switch (plat_dat->interface) {
+ case PHY_INTERFACE_MODE_MII:
+ val = SYSCFG_MCU_ETH_SEL_MII;
+ pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ val = SYSCFG_MCU_ETH_SEL_RMII;
+ pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
+ break;
+ default:
+ pr_debug("SYSCFG init : Do not manage %d interface\n",
+ plat_dat->interface);
+ /* Do not manage others interfaces */
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(dwmac->regmap, reg,
+ dwmac->ops->syscfg_eth_mask, val);
+}
+
static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac)
{
clk_disable_unprepare(dwmac->clk_tx);
clk_disable_unprepare(dwmac->clk_rx);
+
+ if (dwmac->ops->clk_prepare)
+ dwmac->ops->clk_prepare(dwmac, false);
}
static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac,
@@ -70,15 +204,22 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac,
/* Get TX/RX clocks */
dwmac->clk_tx = devm_clk_get(dev, "mac-clk-tx");
if (IS_ERR(dwmac->clk_tx)) {
- dev_err(dev, "No tx clock provided...\n");
+ dev_err(dev, "No ETH Tx clock provided...\n");
return PTR_ERR(dwmac->clk_tx);
}
+
dwmac->clk_rx = devm_clk_get(dev, "mac-clk-rx");
if (IS_ERR(dwmac->clk_rx)) {
- dev_err(dev, "No rx clock provided...\n");
+ dev_err(dev, "No ETH Rx clock provided...\n");
return PTR_ERR(dwmac->clk_rx);
}
+ if (dwmac->ops->parse_data) {
+ err = dwmac->ops->parse_data(dwmac, dev);
+ if (err)
+ return err;
+ }
+
/* Get mode register */
dwmac->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon");
if (IS_ERR(dwmac->regmap))
@@ -91,11 +232,46 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac,
return err;
}
+static int stm32mp1_parse_data(struct stm32_dwmac *dwmac,
+ struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+
+ dwmac->int_phyclk = of_property_read_bool(np, "st,int-phyclk");
+
+ /* Check if internal clk from RCC selected */
+ if (dwmac->int_phyclk) {
+ /* Get ETH_CLK clocks */
+ dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck");
+ if (IS_ERR(dwmac->clk_eth_ck)) {
+ dev_err(dev, "No ETH CK clock provided...\n");
+ return PTR_ERR(dwmac->clk_eth_ck);
+ }
+ }
+
+ /* Clock used for low power mode */
+ dwmac->clk_ethstp = devm_clk_get(dev, "ethstp");
+ if (IS_ERR(dwmac->clk_ethstp)) {
+ dev_err(dev, "No ETH peripheral clock provided for CStop mode ...\n");
+ return PTR_ERR(dwmac->clk_ethstp);
+ }
+
+ /* Clock for sysconfig */
+ dwmac->syscfg_clk = devm_clk_get(dev, "syscfg-clk");
+ if (IS_ERR(dwmac->syscfg_clk)) {
+ dev_err(dev, "No syscfg clock provided...\n");
+ return PTR_ERR(dwmac->syscfg_clk);
+ }
+
+ return 0;
+}
+
static int stm32_dwmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
struct stmmac_resources stmmac_res;
struct stm32_dwmac *dwmac;
+ const struct stm32_ops *data;
int ret;
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
@@ -112,6 +288,16 @@ static int stm32_dwmac_probe(struct platform_device *pdev)
goto err_remove_config_dt;
}
+ data = of_device_get_match_data(&pdev->dev);
+ if (!data) {
+ dev_err(&pdev->dev, "no of match data provided\n");
+ ret = -EINVAL;
+ goto err_remove_config_dt;
+ }
+
+ dwmac->ops = data;
+ dwmac->dev = &pdev->dev;
+
ret = stm32_dwmac_parse_data(dwmac, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Unable to parse OF data\n");
@@ -149,15 +335,48 @@ static int stm32_dwmac_remove(struct platform_device *pdev)
return ret;
}
+static int stm32mp1_suspend(struct stm32_dwmac *dwmac)
+{
+ int ret = 0;
+
+ ret = clk_prepare_enable(dwmac->clk_ethstp);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(dwmac->clk_tx);
+ clk_disable_unprepare(dwmac->syscfg_clk);
+ if (dwmac->int_phyclk)
+ clk_disable_unprepare(dwmac->clk_eth_ck);
+
+ return ret;
+}
+
+static void stm32mp1_resume(struct stm32_dwmac *dwmac)
+{
+ clk_disable_unprepare(dwmac->clk_ethstp);
+}
+
+static int stm32mcu_suspend(struct stm32_dwmac *dwmac)
+{
+ clk_disable_unprepare(dwmac->clk_tx);
+ clk_disable_unprepare(dwmac->clk_rx);
+
+ return 0;
+}
+
#ifdef CONFIG_PM_SLEEP
static int stm32_dwmac_suspend(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
+ struct stm32_dwmac *dwmac = priv->plat->bsp_priv;
+
int ret;
ret = stmmac_suspend(dev);
- stm32_dwmac_clk_disable(priv->plat->bsp_priv);
+
+ if (dwmac->ops->suspend)
+ ret = dwmac->ops->suspend(dwmac);
return ret;
}
@@ -166,8 +385,12 @@ static int stm32_dwmac_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
+ struct stm32_dwmac *dwmac = priv->plat->bsp_priv;
int ret;
+ if (dwmac->ops->resume)
+ dwmac->ops->resume(dwmac);
+
ret = stm32_dwmac_init(priv->plat);
if (ret)
return ret;
@@ -181,8 +404,24 @@ static int stm32_dwmac_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops,
stm32_dwmac_suspend, stm32_dwmac_resume);
+static struct stm32_ops stm32mcu_dwmac_data = {
+ .set_mode = stm32mcu_set_mode,
+ .suspend = stm32mcu_suspend,
+ .syscfg_eth_mask = SYSCFG_MCU_ETH_MASK
+};
+
+static struct stm32_ops stm32mp1_dwmac_data = {
+ .set_mode = stm32mp1_set_mode,
+ .clk_prepare = stm32mp1_clk_prepare,
+ .suspend = stm32mp1_suspend,
+ .resume = stm32mp1_resume,
+ .parse_data = stm32mp1_parse_data,
+ .syscfg_eth_mask = SYSCFG_MP1_ETH_MASK
+};
+
static const struct of_device_id stm32_dwmac_match[] = {
- { .compatible = "st,stm32-dwmac"},
+ { .compatible = "st,stm32-dwmac", .data = &stm32mcu_dwmac_data},
+ { .compatible = "st,stm32mp1-dwmac", .data = &stm32mp1_dwmac_data},
{ }
};
MODULE_DEVICE_TABLE(of, stm32_dwmac_match);
@@ -199,5 +438,6 @@ static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops,
module_platform_driver(stm32_dwmac_driver);
MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@gmail.com>");
-MODULE_DESCRIPTION("STMicroelectronics MCU DWMAC Specific Glue layer");
+MODULE_AUTHOR("Christophe Roullier <christophe.roullier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 DWMAC Specific Glue layer");
MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH V3 0/8] net: ethernet: stmmac: add support for stm32mp1
From: Christophe Roullier @ 2018-05-21 8:07 UTC (permalink / raw)
To: mark.rutland, mcoquelin.stm32, alexandre.torgue, peppe.cavallaro
Cc: devicetree, linux-arm-kernel, netdev, christophe.roullier, andrew
Patches to have Ethernet support on stm32mp1
Changelog:
Remark from Rob Herring
In Documentation/devicetree/bindings/arm/stm32.txt:
In arch/arm/boot/dts/stm32mp157c.dtsi:
Add "st,stm32mp157-syscfg" compatible
Christophe Roullier (8):
net: ethernet: stmmac: add adaptation for stm32mp157c.
dt-bindings: stm32-dwmac: add support of MPU families
ARM: dts: stm32: add ethernet pins to stm32mp157c
ARM: dts: stm32: Add syscfg on stm32mp1
ARM: dts: stm32: Add ethernet dwmac on stm32mp1
net: stmmac: add dwmac-4.20a compatible
ARM: dts: stm32: add support of ethernet on stm32mp157c-ev1
dt-bindings: stm32: add compatible for syscon
Documentation/devicetree/bindings/arm/stm32.txt | 5 +
.../devicetree/bindings/net/stm32-dwmac.txt | 18 +-
arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 46 ++++
arch/arm/boot/dts/stm32mp157c-ev1.dts | 20 ++
arch/arm/boot/dts/stm32mp157c.dtsi | 35 +++
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 270 +++++++++++++++++++--
.../net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 +-
7 files changed, 379 insertions(+), 18 deletions(-)
--
1.9.1
^ permalink raw reply
* Re: [PATCH 05/15] drm/sun4i: Add TCON TOP driver
From: Maxime Ripard @ 2018-05-21 8:05 UTC (permalink / raw)
To: Jernej Skrabec
Cc: wens-jdAy2FN1RRM, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20180519183127.2718-6-jernej.skrabec-gGgVlfcn5nU@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 9866 bytes --]
On Sat, May 19, 2018 at 08:31:17PM +0200, Jernej Skrabec wrote:
> As already described in DT binding, TCON TOP is responsible for
> configuring display pipeline. In this initial driver focus is on HDMI
> pipeline, so TVE and LCD configuration is not implemented.
>
> Implemented features:
> - HDMI source selection
> - clock driver (TCON and DSI gating)
> - connecting mixers and TCONS
>
> Something similar also existed in previous SoCs, except that it was part
> of first TCON.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec-gGgVlfcn5nU@public.gmane.org>
> ---
> drivers/gpu/drm/sun4i/Makefile | 3 +-
> drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 256 +++++++++++++++++++++
> drivers/gpu/drm/sun4i/sun8i_tcon_top.h | 20 ++
> include/dt-bindings/clock/sun8i-tcon-top.h | 11 +
> 4 files changed, 289 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> create mode 100644 include/dt-bindings/clock/sun8i-tcon-top.h
>
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 2589f4acd5ae..09fbfd6304ba 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -16,7 +16,8 @@ sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o
>
> sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
> sun8i_vi_layer.o sun8i_ui_scaler.o \
> - sun8i_vi_scaler.o sun8i_csc.o
> + sun8i_vi_scaler.o sun8i_csc.o \
> + sun8i_tcon_top.o
>
> sun4i-tcon-y += sun4i_crtc.o
> sun4i-tcon-y += sun4i_dotclock.o
> diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> new file mode 100644
> index 000000000000..075a356a6dfa
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> @@ -0,0 +1,256 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* Copyright (c) 2018 Jernej Skrabec <jernej.skrabec-gGgVlfcn5nU@public.gmane.org> */
> +
> +#include <drm/drmP.h>
> +
> +#include <dt-bindings/clock/sun8i-tcon-top.h>
> +
> +#include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/spinlock.h>
> +
> +#include "sun8i_tcon_top.h"
> +
> +#define TCON_TOP_PORT_SEL_REG 0x1C
> +#define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0)
> +#define TCON_TOP_PORT_DE1_MSK GENMASK(5, 4)
> +#define TCON_TOP_PORT_TCON_LCD0 0
> +#define TCON_TOP_PORT_TCON_LCD1 1
> +#define TCON_TOP_PORT_TCON_TV0 2
> +#define TCON_TOP_PORT_TCON_TV1 3
> +
> +#define TCON_TOP_GATE_SRC_REG 0x20
> +#define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28)
> +#define TCON_TOP_HDMI_SRC_NONE 0
> +#define TCON_TOP_HDMI_SRC_TCON_TV0 1
> +#define TCON_TOP_HDMI_SRC_TCON_TV1 2
> +#define TCON_TOP_TCON_TV1_GATE 24
> +#define TCON_TOP_TCON_TV0_GATE 20
> +#define TCON_TOP_TCON_DSI_GATE 16
> +
> +#define CLK_NUM 3
> +
> +struct sun8i_tcon_top {
> + struct clk *bus;
> + void __iomem *regs;
> + struct reset_control *rst;
> +
> + /*
> + * spinlock is used for locking access to registers from different
> + * places - tcon driver and clk subsystem.
> + */
> + spinlock_t reg_lock;
> +};
> +
> +struct sun8i_tcon_top_gate {
> + const char *name;
> + u8 bit;
> + int index;
> +};
> +
> +static const struct sun8i_tcon_top_gate gates[] = {
> + {"bus-tcon-top-dsi", TCON_TOP_TCON_DSI_GATE, CLK_BUS_TCON_TOP_DSI},
> + {"bus-tcon-top-tv0", TCON_TOP_TCON_TV0_GATE, CLK_BUS_TCON_TOP_TV0},
> + {"bus-tcon-top-tv1", TCON_TOP_TCON_TV1_GATE, CLK_BUS_TCON_TOP_TV1},
> +};
> +
> +void sun8i_tcon_top_set_hdmi_src(struct sun8i_tcon_top *tcon_top, int tcon)
> +{
> + unsigned long flags;
> + u32 val;
> +
> + if (tcon > 1) {
> + DRM_ERROR("TCON index is too high!\n");
> + return;
> + }
> +
> + spin_lock_irqsave(&tcon_top->reg_lock, flags);
> +
> + val = readl(tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> + val &= ~TCON_TOP_HDMI_SRC_MSK;
> + val |= FIELD_PREP(TCON_TOP_HDMI_SRC_MSK,
> + TCON_TOP_HDMI_SRC_TCON_TV0 + tcon);
> + writel(val, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> +
> + spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
> +}
> +
> +void sun8i_tcon_top_de_config(struct sun8i_tcon_top *tcon_top,
> + int mixer, enum tcon_type tcon_type, int tcon)
> +{
> + unsigned long flags;
> + u32 val, reg;
> +
> + if (mixer > 1) {
> + DRM_ERROR("Mixer index is too high!\n");
> + return;
> + }
> +
> + if (tcon > 1) {
> + DRM_ERROR("TCON index is too high!\n");
> + return;
> + }
> +
> + switch (tcon_type) {
> + case tcon_type_lcd:
> + val = TCON_TOP_PORT_TCON_LCD0 + tcon;
> + break;
> + case tcon_type_tv:
> + val = TCON_TOP_PORT_TCON_TV0 + tcon;
> + break;
> + default:
> + DRM_ERROR("Invalid TCON type!\n");
> + return;
> + }
> +
> + spin_lock_irqsave(&tcon_top->reg_lock, flags);
> +
> + reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> + if (mixer == 0) {
> + reg &= ~TCON_TOP_PORT_DE0_MSK;
> + reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, val);
> + } else {
> + reg &= ~TCON_TOP_PORT_DE1_MSK;
> + reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, val);
> + }
> + writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> +
> + spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
> +}
> +
> +static int sun8i_tcon_top_probe(struct platform_device *pdev)
> +{
> + struct clk_hw_onecell_data *clk_data;
> + struct sun8i_tcon_top *tcon_top;
> + struct device *dev = &pdev->dev;
> + struct resource *res;
> + int ret, i;
> +
> + tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL);
> + if (!tcon_top)
> + return -ENOMEM;
> +
> + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
> + sizeof(*clk_data->hws) * CLK_NUM,
> + GFP_KERNEL);
> + if (!clk_data)
> + return -ENOMEM;
> +
> + spin_lock_init(&tcon_top->reg_lock);
> +
> + tcon_top->rst = devm_reset_control_get(dev, "rst");
> + if (IS_ERR(tcon_top->rst)) {
> + dev_err(dev, "Couldn't get our reset line\n");
> + return PTR_ERR(tcon_top->rst);
> + }
> +
> + tcon_top->bus = devm_clk_get(dev, "bus");
> + if (IS_ERR(tcon_top->bus)) {
> + dev_err(dev, "Couldn't get the bus clock\n");
> + return PTR_ERR(tcon_top->bus);
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + tcon_top->regs = devm_ioremap_resource(dev, res);
> + if (IS_ERR(tcon_top->regs))
> + return PTR_ERR(tcon_top->regs);
> +
> + ret = reset_control_deassert(tcon_top->rst);
> + if (ret) {
> + dev_err(dev, "Could not deassert ctrl reset control\n");
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(tcon_top->bus);
> + if (ret) {
> + dev_err(dev, "Could not enable bus clock\n");
> + goto err_assert_reset;
> + }
> +
> + /*
> + * Default register values might have some reserved bits set, which
> + * prevents TCON TOP from working properly. Set them to 0 here.
> + */
> + writel(0, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> + writel(0, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> +
> + for (i = 0; i < CLK_NUM; i++) {
> + const char *parent_name = "bus-tcon-top";
I guess retrieving the parent's clock name at runtime would be more
flexible.
> + struct clk_init_data init;
> + struct clk_gate *gate;
> +
> + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
> + if (!gate) {
> + ret = -ENOMEM;
> + goto err_disable_clock;
> + }
> +
> + init.name = gates[i].name;
> + init.ops = &clk_gate_ops;
> + init.flags = CLK_IS_BASIC;
> + init.parent_names = &parent_name;
> + init.num_parents = 1;
> +
> + gate->reg = tcon_top->regs + TCON_TOP_GATE_SRC_REG;
> + gate->bit_idx = gates[i].bit;
> + gate->lock = &tcon_top->reg_lock;
> + gate->hw.init = &init;
> +
> + ret = devm_clk_hw_register(dev, &gate->hw);
> + if (ret)
> + goto err_disable_clock;
Isn't it what clk_hw_register_gate is doing?
> + clk_data->hws[gates[i].index] = &gate->hw;
> + }
> +
> + clk_data->num = CLK_NUM;
> +
> + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
> + if (ret)
> + goto err_disable_clock;
> +
> + platform_set_drvdata(pdev, tcon_top);
> +
> + return 0;
> +
> +err_disable_clock:
> + clk_disable_unprepare(tcon_top->bus);
> +err_assert_reset:
> + reset_control_assert(tcon_top->rst);
> +
> + return ret;
> +}
> +
> +static int sun8i_tcon_top_remove(struct platform_device *pdev)
> +{
> + struct sun8i_tcon_top *tcon_top = platform_get_drvdata(pdev);
> +
> + clk_disable_unprepare(tcon_top->bus);
> + reset_control_assert(tcon_top->rst);
> +
> + return 0;
> +}
> +
> +const struct of_device_id sun8i_tcon_top_of_table[] = {
> + { .compatible = "allwinner,sun8i-r40-tcon-top" },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table);
> +
> +static struct platform_driver sun8i_tcon_top_platform_driver = {
> + .probe = sun8i_tcon_top_probe,
> + .remove = sun8i_tcon_top_remove,
> + .driver = {
> + .name = "sun8i-tcon-top",
> + .of_match_table = sun8i_tcon_top_of_table,
> + },
> +};
> +module_platform_driver(sun8i_tcon_top_platform_driver);
> +
> +MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec-gGgVlfcn5nU@public.gmane.org>");
> +MODULE_DESCRIPTION("Allwinner R40 TCON TOP driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> new file mode 100644
> index 000000000000..19126e07d2a6
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/* Copyright (c) 2018 Jernej Skrabec <jernej.skrabec-gGgVlfcn5nU@public.gmane.org> */
> +
> +#ifndef _SUN8I_TCON_TOP_H_
> +#define _SUN8I_TCON_TOP_H_
> +
> +#include <linux/device.h>
> +
> +struct sun8i_tcon_top;
> +
> +enum tcon_type {
> + tcon_type_lcd,
> + tcon_type_tv,
The usual practice is to have the enum values upper-case.
Thanks!
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH 04/15] dt-bindings: display: sunxi-drm: Add TCON TOP description
From: Maxime Ripard @ 2018-05-21 8:01 UTC (permalink / raw)
To: Jernej Skrabec
Cc: wens-jdAy2FN1RRM, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20180519183127.2718-5-jernej.skrabec-gGgVlfcn5nU@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 2261 bytes --]
Hi,
On Sat, May 19, 2018 at 08:31:16PM +0200, Jernej Skrabec wrote:
> TCON TOP main purpose is to configure whole display pipeline. It
> determines relationships between mixers and TCONs, selects source TCON
> for HDMI, muxes LCD and TV encoder GPIO output,
I'm not sure you mean GPIO here, but rather pin?
> selects TV encoder clock source and contains additional TV TCON and
> DSI gates.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec-gGgVlfcn5nU@public.gmane.org>
> ---
> .../bindings/display/sunxi/sun4i-drm.txt | 20 +++++++++++++++++++
> 1 file changed, 20 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> index 3346c1e2a7a0..a099957ab62a 100644
> --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> @@ -187,6 +187,26 @@ And on the A23, A31, A31s and A33, you need one more clock line:
> - 'lvds-alt': An alternative clock source, separate from the TCON channel 0
> clock, that can be used to drive the LVDS clock
>
> +TCON TOP
> +--------
> +
> +TCON TOPs main purpose is to configure whole display pipeline. It determines
> +relationships between mixers and TCONs, selects source TCON for HDMI, muxes
> +LCD and TV encoder GPIO output, selects TV encoder clock source and contains
> +additional TV TCON and DSI gates.
> +
> +Required properties:
> + - compatible: value must be one of:
> + * allwinner,sun8i-r40-tcon-top
> + - reg: base address and size of the memory-mapped region.
> + - clocks: phandle to the clocks feeding the TCON TOP
> + * bus: TCON TOP interface clock
> + - clock-names: clock name mentioned above
> + - resets: phandle to the reset line driving the DRC
> + * rst: TCON TOP reset line
> + - reset-names: reset name mentioned above
> + - #clock-cells : must contain 1
> +
I guess you should better describe the OF-graph endpoints, and the
clocks output. Just using the binding additions here doesn't allow to
get a clear idea of how the DT should look like.
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox