* [PATCH 6/6] arm64: dts: k3-j721e: Add gpio-keys on common processor board
From: Lokesh Vutla @ 2019-08-09 8:29 UTC (permalink / raw)
To: Tero Kristo, Nishanth Menon, linus.walleij
Cc: Device Tree Mailing List, Lokesh Vutla, Keerthy, linux-gpio,
Rob Herring, Linux ARM Mailing List
In-Reply-To: <20190809082947.30590-1-lokeshvutla@ti.com>
From: Nikhil Devshatwar <nikhil.nd@ti.com>
Common processor board for K3 J721E platform has two push buttons
namely SW10 and SW11.
Add a gpio-keys device node to model them as input keys in Linux.
Add required pinmux nodes to set GPIO pins as input.
Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
.../dts/ti/k3-j721e-common-proc-board.dts | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
index 509579ca3db2..d2894d55fbbe 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
@@ -6,12 +6,49 @@
/dts-v1/;
#include "k3-j721e-som-p0.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
/ {
chosen {
stdout-path = "serial2:115200n8";
bootargs = "console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000";
};
+
+ gpio_keys: gpio-keys {
+ compatible = "gpio-keys";
+ autorepeat;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sw10_button_pins_default &sw11_button_pins_default>;
+
+ sw10: sw10 {
+ label = "GPIO Key USER1";
+ linux,code = <BTN_0>;
+ gpios = <&main_gpio0 0 GPIO_ACTIVE_LOW>;
+ };
+
+ sw11: sw11 {
+ label = "GPIO Key USER2";
+ linux,code = <BTN_1>;
+ gpios = <&wkup_gpio0 7 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
+
+&main_pmx0 {
+ sw10_button_pins_default: sw10_button_pins_default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x0, PIN_INPUT, 7) /* (AC18) EXTINTn.GPIO0_0 */
+ >;
+ };
+};
+
+&wkup_pmx0 {
+ sw11_button_pins_default: sw11_button_pins_default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0xcc, PIN_INPUT, 7) /* (G28) WKUP_GPIO0_7 */
+ >;
+ };
};
&wkup_uart0 {
--
2.22.0
^ permalink raw reply related
* Re: [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support
From: Marco Felsch @ 2019-08-09 8:59 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Hans Verkuil, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
laurent.pinchart, linux-media, devicetree, kernel, Jacopo Mondi
In-Reply-To: <20190514152004.30d7838b@coco.lan>
Hi Mauro, Hans,
On 19-05-14 15:20, Mauro Carvalho Chehab wrote:
> Em Mon, 6 May 2019 12:10:41 +0200
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
>
> > On 4/15/19 2:44 PM, Marco Felsch wrote:
> > > The patch adds the initial connector parsing code, so we can move from a
> > > driver specific parsing code to a generic one. Currently only the
> > > generic fields and the analog-connector specific fields are parsed. Parsing
> > > the other connector specific fields can be added by a simple callbacks.
> > >
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > > ---
> > > [1] https://patchwork.kernel.org/cover/10794703/
> > >
> > > v6:
> > > - use 'unsigned int' count var
> > > - fix comment and style issues
> > > - place '/* fall through */' to correct places
> > > - fix error handling and cleanup by releasing fwnode
> > > - drop vga and dvi parsing support as those connectors are rarely used
> > > these days
> > >
> > > v5:
> > > - s/strlcpy/strscpy/
> > >
> > > v2-v4:
> > > - nothing since the patch was squashed from series [1] into this
> > > series.
> > >
> > > drivers/media/v4l2-core/v4l2-fwnode.c | 111 ++++++++++++++++++++++++++
> > > include/media/v4l2-fwnode.h | 16 ++++
> > > 2 files changed, 127 insertions(+)
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > index 20571846e636..f1cca95c8fef 100644
> > > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > @@ -592,6 +592,117 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> > > }
> > > EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> > >
> > > +static const struct v4l2_fwnode_connector_conv {
> > > + enum v4l2_connector_type type;
> > > + const char *name;
> > > +} connectors[] = {
> > > + {
> > > + .type = V4L2_CON_COMPOSITE,
> > > + .name = "composite-video-connector",
> > > + }, {
> > > + .type = V4L2_CON_SVIDEO,
> > > + .name = "svideo-connector",
> > > + }, {
> > > + .type = V4L2_CON_HDMI,
> > > + .name = "hdmi-connector",
> > > + },
> > > +};
> > > +
> > > +static enum v4l2_connector_type
> > > +v4l2_fwnode_string_to_connector_type(const char *con_str)
> > > +{
> > > + unsigned int i;
> > > +
> > > + for (i = 0; i < ARRAY_SIZE(connectors); i++)
> > > + if (!strcmp(con_str, connectors[i].name))
> > > + return connectors[i].type;
> > > +
> > > + /* no valid connector found */
> > > + return V4L2_CON_UNKNOWN;
> > > +}
> > > +
> > > +static int
> > > +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> > > + struct v4l2_fwnode_connector *vc)
> > > +{
> > > + u32 tvnorms;
> > > + int ret;
> > > +
> > > + ret = fwnode_property_read_u32(fwnode, "tvnorms", &tvnorms);
> > > +
> > > + /* tvnorms is optional */
> > > + vc->connector.analog.supported_tvnorms = ret ? V4L2_STD_ALL : tvnorms;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +int v4l2_fwnode_parse_connector(struct fwnode_handle *__fwnode,
> > > + struct v4l2_fwnode_connector *connector)
> > > +{
> > > + struct fwnode_handle *fwnode;
> > > + struct fwnode_endpoint __ep;
> > > + const char *c_type_str, *label;
> > > + int ret;
> > > +
> > > + memset(connector, 0, sizeof(*connector));
> > > +
> > > + fwnode = fwnode_graph_get_remote_port_parent(__fwnode);
> > > + if (!fwnode)
> > > + return -EINVAL;
> > > +
> > > + /* parse all common properties first */
> > > + /* connector-type is stored within the compatible string */
> > > + ret = fwnode_property_read_string(fwnode, "compatible", &c_type_str);
> > > + if (ret) {
> > > + fwnode_handle_put(fwnode);
> > > + return -EINVAL;
> > > + }
> > > +
> > > + connector->type = v4l2_fwnode_string_to_connector_type(c_type_str);
> > > +
> > > + fwnode_graph_parse_endpoint(__fwnode, &__ep);
> > > + connector->remote_port = __ep.port;
> > > + connector->remote_id = __ep.id;
> > > +
> > > + ret = fwnode_property_read_string(fwnode, "label", &label);
> > > + if (!ret) {
> > > + /* ensure label doesn't exceed V4L2_CONNECTOR_MAX_LABEL size */
> > > + strscpy(connector->label, label, V4L2_CONNECTOR_MAX_LABEL);
> > > + } else {
> > > + /*
> > > + * labels are optional, if none is given create one:
> > > + * <connector-type-string>@port<endpoint_port>/ep<endpoint_id>
> > > + */
> > > + snprintf(connector->label, V4L2_CONNECTOR_MAX_LABEL,
> > > + "%s@port%u/ep%u", c_type_str, connector->remote_port,
> > > + connector->remote_id);
> > > + }
> > > +
> > > + /* now parse the connector specific properties */
> > > + switch (connector->type) {
> > > + case V4L2_CON_COMPOSITE:
> > > + /* fall through */
> > > + case V4L2_CON_SVIDEO:
> > > + ret = v4l2_fwnode_connector_parse_analog(fwnode, connector);
> > > + break;
> > > + case V4L2_CON_HDMI:
> > > + pr_warn("Connector specific parsing is currently not supported for %s\n",
> > > + c_type_str);
> >
> > Why warn? Just drop this.
Wanted to cache all cases here without adding hdmi handling.
> good point. I would prefer to have some warning here, in order to warn a
> developer that might be using it that this part of the code would require
> some change.
>
> perhaps pr_warn_once()?
Okay, I will change it to pr_warn_once().
Regards,
Marco
> >
> > > + ret = 0;
> > > + break;
> > > + case V4L2_CON_UNKNOWN:
> > > + /* fall through */
> > > + default:
> > > + pr_err("Unknown connector type\n");
> > > + ret = -EINVAL;
> > > + };
> > > +
> > > + fwnode_handle_put(fwnode);
> > > +
> > > + return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_connector);
> > > +
> > > static int
> > > v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
> > > struct v4l2_async_notifier *notifier,
> > > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > > index f4df1b95c5ef..e072f2915ddb 100644
> > > --- a/include/media/v4l2-fwnode.h
> > > +++ b/include/media/v4l2-fwnode.h
> > > @@ -269,6 +269,22 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> > > */
> > > void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> > >
> > > +/**
> > > + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> > > + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> > > + * connected to
> > > + * @connector: pointer to the V4L2 fwnode connector data structure
> > > + *
> > > + * Fill the connector data structure with the connector type, label and the
> > > + * endpoint id and port where the connector belongs to. If no label is present
> > > + * a unique one will be created. Labels with more than 40 characters are cut.
> > > + *
> > > + * Return: %0 on success or a negative error code on failure:
> > > + * %-EINVAL on parsing failure
> > > + */
> > > +int v4l2_fwnode_parse_connector(struct fwnode_handle *fwnode,
> > > + struct v4l2_fwnode_connector *connector);
> > > +
> > > /**
> > > * typedef parse_endpoint_func - Driver's callback function to be called on
> > > * each V4L2 fwnode endpoint.
> > >
> >
> > Regards,
> >
> > Hans
>
>
>
> Thanks,
> Mauro
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [linux-sunxi] [PATCH v8 4/4] arm64: dts: allwinner: orange-pi-3: Enable HDMI output
From: Ondřej Jirman @ 2019-08-09 9:04 UTC (permalink / raw)
To: Code Kipper
Cc: linux-sunxi, Maxime Ripard, Chen-Yu Tsai, Rob Herring,
Jernej Škrabec, David Airlie, Daniel Vetter, Mark Rutland,
dri-devel, devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <CAEKpxBn1nF0t-M34iRSy1yYEuUxgNMUXFBhtjXBY8Qk+43zbDQ@mail.gmail.com>
On Fri, Aug 09, 2019 at 10:25:32AM +0200, Code Kipper wrote:
> On Tue, 6 Aug 2019 at 17:57, <megous@megous.com> wrote:
> >
> > From: Ondrej Jirman <megous@megous.com>
> >
> > Orange Pi 3 has a DDC_CEC_EN signal connected to PH2, that enables the DDC
> > I2C bus voltage shifter. Before EDID can be read, we need to pull PH2 high.
> > This is realized by the ddc-en-gpios property.
> Great work. Is there any chance you can move this to the
> arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi?, as all the H6
> based orange-pi's have this feature.
I plan to do that as a followup patch, once this is merged.
regards,
o.
> BR,
> CK
> >
> > Signed-off-by: Ondrej Jirman <megous@megous.com>
> > ---
> > .../dts/allwinner/sun50i-h6-orangepi-3.dts | 26 +++++++++++++++++++
> > 1 file changed, 26 insertions(+)
> >
> > diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
> > index 2c6807b74ff6..01bb1bafe284 100644
> > --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
> > +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
> > @@ -22,6 +22,18 @@
> > stdout-path = "serial0:115200n8";
> > };
> >
> > + connector {
> > + compatible = "hdmi-connector";
> > + ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
> > + type = "a";
> > +
> > + port {
> > + hdmi_con_in: endpoint {
> > + remote-endpoint = <&hdmi_out_con>;
> > + };
> > + };
> > + };
> > +
> > leds {
> > compatible = "gpio-leds";
> >
> > @@ -72,6 +84,10 @@
> > cpu-supply = <®_dcdca>;
> > };
> >
> > +&de {
> > + status = "okay";
> > +};
> > +
> > &ehci0 {
> > status = "okay";
> > };
> > @@ -91,6 +107,16 @@
> > status = "okay";
> > };
> >
> > +&hdmi {
> > + status = "okay";
> > +};
> > +
> > +&hdmi_out {
> > + hdmi_out_con: endpoint {
> > + remote-endpoint = <&hdmi_con_in>;
> > + };
> > +};
> > +
> > &mdio {
> > ext_rgmii_phy: ethernet-phy@1 {
> > compatible = "ethernet-phy-ieee802.3-c22";
> > --
> > 2.22.0
> >
> > --
> > You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> > To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> > To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20190806155744.10263-5-megous%40megous.com.
^ permalink raw reply
* Re: [PATCH 2/2] pwm: sprd: Add Spreadtrum PWM support
From: Uwe Kleine-König @ 2019-08-09 9:10 UTC (permalink / raw)
To: Baolin Wang
Cc: thierry.reding, robh+dt, mark.rutland, orsonzhai, zhang.lyra,
vincent.guittot, linux-pwm, devicetree, linux-kernel, kernel
In-Reply-To: <40127356a1acd1f2ff1be1d8a120b305a4e17af4.1565168564.git.baolin.wang@linaro.org>
On Thu, Aug 08, 2019 at 04:59:39PM +0800, Baolin Wang wrote:
> From: Neo Hou <neo.hou@unisoc.com>
>
> This patch adds the Spreadtrum PWM support, which provides maximum 4
> channels.
>
> Signed-off-by: Neo Hou <neo.hou@unisoc.com>
> Co-developed-by: Baolin Wang <baolin.wang@linaro.org>
> Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
> ---
> drivers/pwm/Kconfig | 10 ++
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-sprd.c | 311 ++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 322 insertions(+)
> create mode 100644 drivers/pwm/pwm-sprd.c
>
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index a7e5751..4963b4d 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -423,6 +423,16 @@ config PWM_SPEAR
> To compile this driver as a module, choose M here: the module
> will be called pwm-spear.
>
> +config PWM_SPRD
> + tristate "Spreadtrum PWM support"
> + depends on ARCH_SPRD || COMPILE_TEST
I think you need
depends on HAS_IOMEM
> + help
> + Generic PWM framework driver for the PWM controller on
> + Spreadtrum SoCs.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called pwm-sprd.
> +
> config PWM_STI
> tristate "STiH4xx PWM support"
> depends on ARCH_STI
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 76b555b..26326ad 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
> obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
> obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
> obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
> +obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o
> obj-$(CONFIG_PWM_STI) += pwm-sti.o
> obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
> obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o
> diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c
> new file mode 100644
> index 0000000..f6fc793
> --- /dev/null
> +++ b/drivers/pwm/pwm-sprd.c
> @@ -0,0 +1,311 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 Spreadtrum Communications Inc.
If there is a publicly available reference manual available, please add
a link to it here.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/math64.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +
> +#define SPRD_PWM_PRESCALE 0x0
> +#define SPRD_PWM_MOD 0x4
> +#define SPRD_PWM_DUTY 0x8
> +#define SPRD_PWM_DIV 0xc
> +#define SPRD_PWM_PAT_LOW 0x10
> +#define SPRD_PWM_PAT_HIGH 0x14
> +#define SPRD_PWM_ENABLE 0x18
> +
> +#define SPRD_PWM_MOD_MAX GENMASK(7, 0)
> +#define SPRD_PWM_REG_MSK GENMASK(15, 0)
> +#define SPRD_PWM_ENABLE_BIT BIT(0)
> +
> +#define SPRD_PWM_NUM 4
> +#define SPRD_PWM_REGS_SHIFT 5
> +#define SPRD_PWM_NUM_CLKS 2
> +#define SPRD_PWM_DEFAULT_CLK 26000000UL
> +
> +struct sprd_pwm_chn {
> + struct clk_bulk_data clks[SPRD_PWM_NUM_CLKS];
> + unsigned long clk_rate;
> + bool clk_enabled;
> +};
> +
> +struct sprd_pwm_chip {
> + void __iomem *base;
> + struct device *dev;
> + struct pwm_chip chip;
> + int num_pwms;
> + struct sprd_pwm_chn chn[SPRD_PWM_NUM];
> +};
> +
> +/* list of clocks required by PWM channels */
> +static const char * const sprd_pwm_clks[] = {
> + "enable0", "pwm0",
> + "enable1", "pwm1",
> + "enable2", "pwm2",
> + "enable3", "pwm3",
> +};
> +
> +static u32 sprd_pwm_read(struct sprd_pwm_chip *chip, u32 num, u32 reg)
num is the channel id here? Then maybe "hwid" or "chanid" would be a
better name. Or pass struct pwm_chip only?
Please (if you keep sprd_pwm_chip) rename chip to spc which is the name
used in other places for structures of this type. "chip" is for struct
pwm_chip.
> +{
> + u32 offset = reg + (num << SPRD_PWM_REGS_SHIFT);
> +
> + return readl_relaxed(chip->base + offset);
> +}
> +
> +static void sprd_pwm_write(struct sprd_pwm_chip *chip, u32 num,
> + u32 reg, u32 val)
> +{
> + u32 offset = reg + (num << SPRD_PWM_REGS_SHIFT);
> +
> + writel_relaxed(val, chip->base + offset);
> +}
> +
> +static int sprd_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> + int duty_ns, int period_ns)
Please implement .apply() instead of .config(), .enable() and
.disable().
> +{
> + struct sprd_pwm_chip *spc =
> + container_of(chip, struct sprd_pwm_chip, chip);
> + struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];
> + u64 div, tmp;
> + u32 prescale, duty;
> + int ret;
> +
> + /*
> + * NOTE: the clocks to PWM channel has to be enabled first before
> + * writing to the registers.
> + */
> + if (!chn->clk_enabled) {
> + ret = clk_bulk_prepare_enable(SPRD_PWM_NUM_CLKS, chn->clks);
Do you really need to enable all 8 clocks to configure a single channel?
> + if (ret) {
> + dev_err(spc->dev, "failed to enable pwm%u clock\n",
> + pwm->hwpwm);
> + return ret;
> + }
> +
> + chn->clk_enabled = true;
> + }
> +
> + duty = duty_ns * SPRD_PWM_MOD_MAX / period_ns;
@Baolin: until we're there that there are framework requirements how to
round, please document at least how you do it here. Also describing the
underlying concepts would be good for the driver reader.
Something like:
/*
* The hardware provides a counter that is feed by the source clock.
* The period length is (PRESCALE + 1) * MOD counter steps.
* The duty cycle length is (PRESCALE + 1) * DUTY counter steps.
*
* To keep the maths simple we're always using MOD = MOD_MAX.
* The value for PRESCALE is selected such that the resulting period
* gets the maximal length not bigger than the requested one with the
* given settings (MOD = MOD_MAX and input clock).
*/
@Thierry: having a framework guideline here would be good. Or still
better a guideline and a debug setting that notices drivers stepping out
of line.
I assume using MOD = 0 is forbidden?
> + /*
> + * According to the datasheet, the period_ns calculation formula
> + * should be:
> + * period_ns = 10^9 * (prescale + 1) * mod / clk_rate
> + *
> + * Then we can get the prescale formula:
> + * prescale = (period_ns * clk_rate) / (10^9 * mod) -1
> + */
> + tmp = chn->clk_rate * period_ns;
> + div = 1000000000ULL * SPRD_PWM_MOD_MAX;
Please use NSEC_PER_SEC instead of 1000000000ULL.
> + prescale = div64_u64(tmp, div) - 1;
If tmp is smaller than div you end up with prescale = 0xffffffff which
should be catched. What if prescale > 0xffff?
> + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_MOD, SPRD_PWM_MOD_MAX);
> + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_DUTY, duty);
You're losing precision here as you always use SPRD_PWM_MOD_MAX, right?
(Just for my understanding, if this simpler approach is good enough
here that's fine.)
> + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_PAT_LOW, SPRD_PWM_REG_MSK);
> + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_PAT_HIGH, SPRD_PWM_REG_MSK);
Please describe these two registers in a short comment.
> + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_PRESCALE, prescale);
Is the configuration here atomic in the sense that the write of DUTY
above only gets effective when PRESCALE is written? If not, please add
a describing paragraph at the top of the driver similar to what is
written in pwm-sifive.c. When the PWM is already running before, how
does a configuration change effects the output? Is the currently running
period completed?
> +static void sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
> + struct pwm_state *state)
> +{
> + struct sprd_pwm_chip *spc =
> + container_of(chip, struct sprd_pwm_chip, chip);
> + struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];
> + u32 enabled, duty, prescale;
> + u64 tmp;
> + int ret;
> +
> + ret = clk_bulk_prepare_enable(SPRD_PWM_NUM_CLKS, chn->clks);
> + if (ret) {
> + dev_err(spc->dev, "failed to enable pwm%u clocks\n",
> + pwm->hwpwm);
> + return;
> + }
> +
> + chn->clk_enabled = true;
> +
> + duty = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_DUTY) & SPRD_PWM_REG_MSK;
> + prescale = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_PRESCALE) & SPRD_PWM_REG_MSK;
> + enabled = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_ENABLE) & SPRD_PWM_ENABLE_BIT;
> +
> + /*
> + * According to the datasheet, the period_ns and duty_ns calculation
> + * formula should be:
> + * period_ns = 10^9 * (prescale + 1) * mod / clk_rate
> + * duty_ns = 10^9 * (prescale + 1) * duty / clk_rate
> + */
> + tmp = (prescale + 1) * 1000000000ULL * SPRD_PWM_MOD_MAX;
> + state->period = div64_u64(tmp, chn->clk_rate);
This is not idempotent. If you apply the configuration that is returned
here this shouldn't result in a reconfiguration.
> + tmp = (prescale + 1) * 1000000000ULL * duty;
> + state->duty_cycle = div64_u64(tmp, chn->clk_rate);
> +
> + state->enabled = !!enabled;
> +
> + /* Disable PWM clocks if the PWM channel is not in enable state. */
> + if (!enabled) {
> + clk_bulk_disable_unprepare(SPRD_PWM_NUM_CLKS, chn->clks);
> + chn->clk_enabled = false;
> + }
> +}
> +
> +static const struct pwm_ops sprd_pwm_ops = {
> + .config = sprd_pwm_config,
> + .enable = sprd_pwm_enable,
> + .disable = sprd_pwm_disable,
> + .get_state = sprd_pwm_get_state,
> + .owner = THIS_MODULE,
> +};
> +
> +static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc)
> +{
> + struct clk *clk_parent, *clk_pwm;
> + int ret, i, clk_index = 0;
> +
> + clk_parent = devm_clk_get(spc->dev, "source");
> + if (IS_ERR(clk_parent)) {
> + dev_err(spc->dev, "failed to get source clock\n");
> + return PTR_ERR(clk_parent);
> + }
> +
> + for (i = 0; i < SPRD_PWM_NUM; i++) {
> + struct sprd_pwm_chn *chn = &spc->chn[i];
> + int j;
> +
> + for (j = 0; j < SPRD_PWM_NUM_CLKS; ++j)
> + chn->clks[j].id = sprd_pwm_clks[clk_index++];
> +
> + ret = devm_clk_bulk_get(spc->dev, SPRD_PWM_NUM_CLKS, chn->clks);
> + if (ret) {
> + if (ret == -ENOENT)
> + break;
devm_clk_bulk_get_optional ? I'm sure you don't want to get all 8 clocks
8 times.
> +
> + dev_err(spc->dev, "failed to get channel clocks\n");
> + return ret;
> + }
> +
> + clk_pwm = chn->clks[1].clk;
This 1 looks suspicious. Are you using all clocks provided in the dtb at
all? You're not using i in the loop at all, this doesn't look right.
> + if (!clk_set_parent(clk_pwm, clk_parent))
> + chn->clk_rate = clk_get_rate(clk_pwm);
> + else
> + chn->clk_rate = SPRD_PWM_DEFAULT_CLK;
I don't know all the clock framework details, but I think there are
better ways to ensure that a given clock is used as parent for another
given clock. Please read the chapter about "Assigned clock parents and
rates" in the clock bindings and check if this could be used for the
purpose here and so simplify the driver.
> + }
> +
> + if (!i) {
> + dev_err(spc->dev, "no availbale PWM channels\n");
s/availbale/available/
> + return -EINVAL;
> + }
> +
> + spc->num_pwms = i;
> +
> + return 0;
> +}
> +
> +static int sprd_pwm_probe(struct platform_device *pdev)
> +{
> + struct sprd_pwm_chip *spc;
> + int ret;
> +
> + spc = devm_kzalloc(&pdev->dev, sizeof(*spc), GFP_KERNEL);
> + if (!spc)
> + return -ENOMEM;
> +
> + spc->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(spc->base))
> + return PTR_ERR(spc->base);
> +
> + spc->dev = &pdev->dev;
> + ret = sprd_pwm_clk_init(spc);
> + if (ret)
> + return ret;
> +
> + spc->chip.dev = &pdev->dev;
> + spc->chip.ops = &sprd_pwm_ops;
> + spc->chip.base = -1;
> + spc->chip.npwm = spc->num_pwms;
> +
> + ret = pwmchip_add(&spc->chip);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to add PWM chip\n");
> + return ret;
> + }
> +
> + platform_set_drvdata(pdev, spc);
If you do this earlier you can simplify the last part of the driver to:
ret = pwmchip_add(&spc->chip);
if (ret)
dev_err(&pdev->dev, "failed to add PWM chip\n");
return ret;
> + return 0;
> +}
> +
> +static int sprd_pwm_remove(struct platform_device *pdev)
> +{
> + struct sprd_pwm_chip *spc = platform_get_drvdata(pdev);
> + int i;
> +
> + for (i = 0; i < spc->num_pwms; i++)
> + pwm_disable(&spc->chip.pwms[i]);
This is wrong. You must not call pwm_disable here. It's the consumer's
responsibility to disable the hardware.
> +
> + return pwmchip_remove(&spc->chip);
> +}
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH 0/3] Add basic support for RTC on Allwinner H6 SoC
From: Ondřej Jirman @ 2019-08-09 9:16 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Chen-Yu Tsai, Mark Rutland, Alessandro Zummo, devicetree,
Maxime Ripard, linux-kernel, linux-sunxi, Rob Herring,
linux-arm-kernel, linux-rtc-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20190808233930.GM3600-m++hUPXGwpdeoWH0uzbU5w@public.gmane.org>
On Fri, Aug 09, 2019 at 01:39:30AM +0200, Alexandre Belloni wrote:
> On 08/08/2019 14:12:37+0200, Ondřej Jirman wrote:
> > On Wed, Aug 07, 2019 at 12:55:02PM +0200, Alexandre Belloni wrote:
> > > Hi,
> > >
> > > On 06/08/2019 20:30:45+0200, Ondřej Jirman wrote:
> > > > Maybe whether XO or DCXO is used also matters if you want to do some fine
> > > > tunning of DCXO (control register has pletny of options), but that's probably
> > > > better done in u-boot. And there's still no need to read HOSC source from DT.
> > > > The driver can just check compatible, and if it is H6 and OSC_CLK_SRC_SEL is 1,
> > > > it can do it's DCXO tunning, or whatever. But neither OS nor bootloader will
> > > > be using this info to gate/disable the osciallator.
> > > >
> > >
> > > It is actually useful to be able to tweak the crystal tuning at
> > > runtime to be able to reduce clock drift and compare with a reliable
> > > source (e.g. NTP).
> >
> > I don't think there's a Linux kernel API that you can use to achieve that, so
> > that's a rather theoretical concern at the moment.
> >
>
> There is /sys/class/rtc/rtcX/offset which is even properly documented.
>
> The reason I asked is that some RTCs have both analog (changing the
> oscillator capacitance) and digital (changing the RTC counter) so I'm
> wondering whether this interface should be extended.
As I wrote below, that can't be achieved by tuning DCXO.
> > Also there are multiple clocks, that can drive the RTC, and you usually don't
> > drive it from 24MHz DCXO oscillator. The reason is that you'd have to deal with
> > the fact that the clock for RTC then becomes 24000000/750 (750 is fixed
> > divider), which is 32000.
> >
> > So if you want to get 32768Hz for RTC by tuning the DCXO, it would have to have
> > 24 576 000 Hz. And even if you could achieve that (doubtful), it would throw off
> > timings in the rest of the system (say UART, USB, CPU, display ctl) in a major way.
> >
> > I guess you can try tuning 24MHz oscillator so that it's closer to the
> > real-world 24MHz via NTP reference for other reasons. But it would be
> > complicated, and require precise interaction with other components, like using
> > HW timers sourced from 24MHz HOSC clock, because you can't use CPU's timers,
> > because of inaccuracies introduced during DVFS, for example.
> >
> > regards,
> > o.
> >
> > > I'm curious, what kind of options does this RTC have?
> > >
> > > --
> > > Alexandre Belloni, Bootlin
> > > Embedded Linux and Kernel engineering
> > > https://bootlin.com
> > >
> > > _______________________________________________
> > > linux-arm-kernel mailing list
> > > linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
> --
> Alexandre Belloni, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20190809091626.6kanjbmvbi4oipco%40core.my.home.
^ permalink raw reply
* Re: [PATCH 0/4] ADS7846 add general touchscreen features
From: Marco Felsch @ 2019-08-09 9:30 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt; +Cc: devicetree, kernel, linux-input
In-Reply-To: <20190327133927.1340-1-m.felsch@pengutronix.de>
Hi Dmitry,
gentle ping.
Regards,
Marco
On 19-03-27 14:39, Marco Felsch wrote:
> Hi,
>
> The main purpose of this small set is to add support for the general
> touchscreen dt-properties. During this work I also changed the memory
> allocation methods to the devm_* ones to cleanup the error-paths.
>
> Regards,
> Marco
>
> Marco Felsch (4):
> Input: ads7846 - convert to devm_ alloc functions
> dt-bindings: input: ads7846: fix property description
> dt-bindings: input: ads7846: replace vendor-bindings by general ones
> Input: ads7846 - add support for general touchscreen bindings
>
> .../bindings/input/touchscreen/ads7846.txt | 29 +++++--
> drivers/input/touchscreen/ads7846.c | 75 +++++++++++--------
> 2 files changed, 66 insertions(+), 38 deletions(-)
>
> --
> 2.20.1
>
>
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH 00/19] Initial support for Marvell MMP3 SoC
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk
Hi,
this patch set adds support for the Marvell MMP3 processor. MMP3 is used
in OLPC XO-4 laptops, Panasonic Toughpad FZ-A1 tablet and Dell Wyse 3020
Tx0D thin clients.
Apart from the adjustments in mach-mmp/, the patch makes necessary
changes to the irqchip driver and adds an USB2 PHY driver. The latter
has a dependency on the mach-mmp/ changes, so it can't be submitted
separately.
The patch set has been tested to work on Wyse Tx0D and not ruin MMP2
support on XO-1.75.
Lubo
^ permalink raw reply
* [PATCH 01/19] dt-bindings: arm: cpu: Add Marvell MMP3 SMP enable method
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
Add the enable method for the second PJ4B core of the Marvell MMP3 SoC.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
Documentation/devicetree/bindings/arm/cpus.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml
index aa40b074b8648..fcba84e32e68a 100644
--- a/Documentation/devicetree/bindings/arm/cpus.yaml
+++ b/Documentation/devicetree/bindings/arm/cpus.yaml
@@ -186,6 +186,7 @@ properties:
- marvell,armada-390-smp
- marvell,armada-xp-smp
- marvell,98dx3236-smp
+ - marvell,mmp3-smp
- mediatek,mt6589-smp
- mediatek,mt81xx-tz-smp
- qcom,gcc-msm8660
--
2.21.0
^ permalink raw reply related
* [PATCH 02/19] dt-bindings: arm: mrvl: Document MMP3 compatible string
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
Marvel MMP3 is a successor to MMP2, containing similar peripherals with two
PJ4B cores.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
Documentation/devicetree/bindings/arm/mrvl/mrvl.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
index 951687528efb0..66e1e1414245b 100644
--- a/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
+++ b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
@@ -12,3 +12,7 @@ Required root node properties:
MMP2 Brownstone Board
Required root node properties:
- compatible = "mrvl,mmp2-brownstone", "mrvl,mmp2";
+
+MMP3 SoC
+Required root node properties:
+ - compatible = "marvell,mmp3";
--
2.21.0
^ permalink raw reply related
* [PATCH 03/19] dt-bindings: mrvl,intc: Add a MMP3 interrupt controller
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
Similar to MMP2 one, but has an extra range for the other core. The
muxes stay the same.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
.../interrupt-controller/mrvl,intc.txt | 23 ++++++++++++++-----
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mrvl,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/mrvl,intc.txt
index 608fee15a4cfc..41c131d026f94 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/mrvl,intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/mrvl,intc.txt
@@ -1,13 +1,15 @@
* Marvell MMP Interrupt controller
Required properties:
-- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc" or
- "mrvl,mmp2-mux-intc"
+- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc",
+ "marvell,mmp3-intc", "mrvl,mmp2-mux-intc"
- reg : Address and length of the register set of the interrupt controller.
If the interrupt controller is intc, address and length means the range
- of the whole interrupt controller. If the interrupt controller is mux-intc,
- address and length means one register. Since address of mux-intc is in the
- range of intc. mux-intc is secondary interrupt controller.
+ of the whole interrupt controller. The "marvell,mmp3-intc" controller
+ also has a secondary range for the second CPU core. If the interrupt
+ controller is mux-intc, address and length means one register. Since
+ address of mux-intc is in the range of intc. mux-intc is secondary
+ interrupt controller.
- reg-names : Name of the register set of the interrupt controller. It's
only required in mux-intc interrupt controller.
- interrupts : Should be the port interrupt shared by mux interrupts. It's
@@ -20,7 +22,7 @@ Required properties:
- mrvl,clr-mfp-irq : Specifies the interrupt that needs to clear MFP edge
detection first.
-Example:
+Examples:
intc: interrupt-controller@d4282000 {
compatible = "mrvl,mmp2-intc";
interrupt-controller;
@@ -29,6 +31,15 @@ Example:
mrvl,intc-nr-irqs = <64>;
};
+ intc: interrupt-controller@d4282000 {
+ compatible = "marvell,mmp3-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xd4282000 0x1000>,
+ <0xd4284000 0x100>;
+ mrvl,intc-nr-irqs = <64>;
+ };
+
intcmux4@d4282150 {
compatible = "mrvl,mmp2-mux-intc";
interrupts = <4>;
--
2.21.0
^ permalink raw reply related
* [PATCH 04/19] dt-bindings: phy-mmp3-usb: Add bindings
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
This is the PHY chip for USB OTG on MMP3 platform.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
.../devicetree/bindings/phy/phy-mmp3-usb.txt | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/phy-mmp3-usb.txt
diff --git a/Documentation/devicetree/bindings/phy/phy-mmp3-usb.txt b/Documentation/devicetree/bindings/phy/phy-mmp3-usb.txt
new file mode 100644
index 0000000000000..b9623b98151bc
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-mmp3-usb.txt
@@ -0,0 +1,16 @@
+Marvell MMP3 USB PHY
+--------------------
+
+Required properties:
+- compatible: must be "marvell,mmp3-usb-phy"
+- #phy-cells: must be 0
+
+Example:
+ usb-phy: usbphy@d4207000 {
+ compatible = "marvell,mmp3-usb-phy";
+ reg = <0xd4207000 0x40>;
+ #phy-cells = <0>;
+ };
+
+This document explains the device tree binding. For general information
+about PHY subsystem refer to Documentation/phy.txt
--
2.21.0
^ permalink raw reply related
* [PATCH 05/19] irqchip/mmp: do not use of_address_to_resource() to get mux regs
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel, Pavel Machek
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
The "regs" property of the "mrvl,mmp2-mux-intc" devices are silly. They
are offsets from intc's base, not addresses on the parent bus. At this
point it probably can't be fixed.
On an OLPC XO-1.75 machine, the muxes are children of the intc, not the
axi bus, and thus of_address_to_resource() won't work. We should treat
the values as mere integers as opposed to bus addresses.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
drivers/irqchip/irq-mmp.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 14618dc0bd396..af9cba4a51c2e 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -424,9 +424,9 @@ IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init);
static int __init mmp2_mux_of_init(struct device_node *node,
struct device_node *parent)
{
- struct resource res;
int i, ret, irq, j = 0;
u32 nr_irqs, mfp_irq;
+ u32 reg[4];
if (!parent)
return -ENODEV;
@@ -438,18 +438,20 @@ static int __init mmp2_mux_of_init(struct device_node *node,
pr_err("Not found mrvl,intc-nr-irqs property\n");
return -EINVAL;
}
- ret = of_address_to_resource(node, 0, &res);
+
+ /*
+ * For historical reasonsm, the "regs" property of the
+ * mrvl,mmp2-mux-intc is not a regular * "regs" property containing
+ * addresses on the parent bus, but offsets from the intc's base.
+ * That is why we can't use of_address_to_resource() here.
+ */
+ ret = of_property_read_u32_array(node, "reg", reg, ARRAY_SIZE(reg));
if (ret < 0) {
pr_err("Not found reg property\n");
return -EINVAL;
}
- icu_data[i].reg_status = mmp_icu_base + res.start;
- ret = of_address_to_resource(node, 1, &res);
- if (ret < 0) {
- pr_err("Not found reg property\n");
- return -EINVAL;
- }
- icu_data[i].reg_mask = mmp_icu_base + res.start;
+ icu_data[i].reg_status = mmp_icu_base + reg[0];
+ icu_data[i].reg_mask = mmp_icu_base + reg[2];
icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
if (!icu_data[i].cascade_irq)
return -EINVAL;
--
2.21.0
^ permalink raw reply related
* [PATCH 06/19] irqchip/mmp: add missing chained_irq_{enter,exit}()
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
The lack of chained_irq_exit() leaves the muxed interrupt masked on MMP3.
For reasons unknown this is not a problem on MMP2.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
drivers/irqchip/irq-mmp.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index af9cba4a51c2e..cd8d2253f56d1 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/io.h>
#include <linux/ioport.h>
@@ -132,11 +133,14 @@ struct irq_chip icu_irq_chip = {
static void icu_mux_irq_demux(struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
+ struct irq_chip *chip = irq_get_chip(irq);
struct irq_domain *domain;
struct icu_chip_data *data;
int i;
unsigned long mask, status, n;
+ chained_irq_enter(chip, desc);
+
for (i = 1; i < max_icu_nr; i++) {
if (irq == icu_data[i].cascade_irq) {
domain = icu_data[i].domain;
@@ -146,7 +150,7 @@ static void icu_mux_irq_demux(struct irq_desc *desc)
}
if (i >= max_icu_nr) {
pr_err("Spurious irq %d in MMP INTC\n", irq);
- return;
+ goto out;
}
mask = readl_relaxed(data->reg_mask);
@@ -158,6 +162,9 @@ static void icu_mux_irq_demux(struct irq_desc *desc)
generic_handle_irq(icu_data[i].virq_base + n);
}
}
+
+out:
+ chained_irq_exit(chip, desc);
}
static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
--
2.21.0
^ permalink raw reply related
* [PATCH 07/19] irqchip/mmp: mask off interrupts from other cores
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Andres Salomon, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
From: Andres Salomon <dilinger@queued.net>
On mmp3, there's an extra set of ICU registers (ICU2) that handle
interrupts on the extra cores. When masking off interrupts on MP1,
these should be masked as well.
We add a new interrupt controller via device tree to identify when we're
looking at an mmp3 machine via compatible field of "marvell,mmp3-intc".
[lkundrak@v3.sk: Changed "mrvl,mmp3-intc" compatible strings to
"marvell,mmp3-intc". Tidied up the subject line a bit.]
Signed-off-by: Andres Salomon <dilinger@queued.net>
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
arch/arm/mach-mmp/regs-icu.h | 3 +++
drivers/irqchip/irq-mmp.c | 51 ++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+)
diff --git a/arch/arm/mach-mmp/regs-icu.h b/arch/arm/mach-mmp/regs-icu.h
index 0375d5a7fcb2b..410743d2b4020 100644
--- a/arch/arm/mach-mmp/regs-icu.h
+++ b/arch/arm/mach-mmp/regs-icu.h
@@ -11,6 +11,9 @@
#define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000)
#define ICU_REG(x) (ICU_VIRT_BASE + (x))
+#define ICU2_VIRT_BASE (AXI_VIRT_BASE + 0x84000)
+#define ICU2_REG(x) (ICU2_VIRT_BASE + (x))
+
#define ICU_INT_CONF(n) ICU_REG((n) << 2)
#define ICU_INT_CONF_MASK (0xf)
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index cd8d2253f56d1..25497c75cc861 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -44,6 +44,7 @@ struct icu_chip_data {
unsigned int conf_enable;
unsigned int conf_disable;
unsigned int conf_mask;
+ unsigned int conf2_mask;
unsigned int clr_mfp_irq_base;
unsigned int clr_mfp_hwirq;
struct irq_domain *domain;
@@ -53,9 +54,11 @@ struct mmp_intc_conf {
unsigned int conf_enable;
unsigned int conf_disable;
unsigned int conf_mask;
+ unsigned int conf2_mask;
};
static void __iomem *mmp_icu_base;
+static void __iomem *mmp_icu2_base;
static struct icu_chip_data icu_data[MAX_ICU_NR];
static int max_icu_nr;
@@ -98,6 +101,16 @@ static void icu_mask_irq(struct irq_data *d)
r &= ~data->conf_mask;
r |= data->conf_disable;
writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+
+ if (data->conf2_mask) {
+ /*
+ * ICU1 (above) only controls PJ4 MP1; if using SMP,
+ * we need to also mask the MP2 and MM cores via ICU2.
+ */
+ r = readl_relaxed(mmp_icu2_base + (hwirq << 2));
+ r &= ~data->conf2_mask;
+ writel_relaxed(r, mmp_icu2_base + (hwirq << 2));
+ }
} else {
r = readl_relaxed(data->reg_mask) | (1 << hwirq);
writel_relaxed(r, data->reg_mask);
@@ -201,6 +214,14 @@ static const struct mmp_intc_conf mmp2_conf = {
MMP2_ICU_INT_ROUTE_PJ4_FIQ,
};
+static struct mmp_intc_conf mmp3_conf = {
+ .conf_enable = 0x20,
+ .conf_disable = 0x0,
+ .conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ |
+ MMP2_ICU_INT_ROUTE_PJ4_FIQ,
+ .conf2_mask = 0xf0,
+};
+
static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
{
int hwirq;
@@ -364,6 +385,14 @@ static int __init mmp_init_bases(struct device_node *node)
pr_err("Failed to get interrupt controller register\n");
return -ENOMEM;
}
+ if (of_device_is_compatible(node, "marvell,mmp3-intc")) {
+ mmp_icu2_base = of_iomap(node, 1);
+ if (!mmp_icu2_base) {
+ pr_err("Failed to get interrupt controller register #2\n");
+ iounmap(mmp_icu_base);
+ return -ENOMEM;
+ }
+ }
icu_data[0].virq_base = 0;
icu_data[0].domain = irq_domain_add_linear(node, nr_irqs,
@@ -386,6 +415,8 @@ static int __init mmp_init_bases(struct device_node *node)
irq_dispose_mapping(icu_data[0].virq_base + i);
}
irq_domain_remove(icu_data[0].domain);
+ if (of_device_is_compatible(node, "marvell,mmp3-intc"))
+ iounmap(mmp_icu2_base);
iounmap(mmp_icu_base);
return -EINVAL;
}
@@ -428,6 +459,26 @@ static int __init mmp2_of_init(struct device_node *node,
}
IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init);
+static int __init mmp3_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ int ret;
+
+ ret = mmp_init_bases(node);
+ if (ret < 0)
+ return ret;
+
+ icu_data[0].conf_enable = mmp3_conf.conf_enable;
+ icu_data[0].conf_disable = mmp3_conf.conf_disable;
+ icu_data[0].conf_mask = mmp3_conf.conf_mask;
+ icu_data[0].conf2_mask = mmp3_conf.conf2_mask;
+ irq_set_default_host(icu_data[0].domain);
+ set_handle_irq(mmp2_handle_irq);
+ max_icu_nr = 1;
+ return 0;
+}
+IRQCHIP_DECLARE(mmp3_intc, "marvell,mmp3-intc", mmp3_of_init);
+
static int __init mmp2_mux_of_init(struct device_node *node,
struct device_node *parent)
{
--
2.21.0
^ permalink raw reply related
* [PATCH 08/19] irqchip/mmp: coexist with GIC root IRQ controller
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
On MMP3, the GIC can be set as a root IRQ interrupt controller. If the
device tree indicated that GIC is enabled, avoid hooking up
mmp2_handle_irq().
The interrupt muxes are still being used.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
drivers/irqchip/irq-mmp.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 25497c75cc861..28feb0f393056 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -472,8 +472,13 @@ static int __init mmp3_of_init(struct device_node *node,
icu_data[0].conf_disable = mmp3_conf.conf_disable;
icu_data[0].conf_mask = mmp3_conf.conf_mask;
icu_data[0].conf2_mask = mmp3_conf.conf2_mask;
- irq_set_default_host(icu_data[0].domain);
- set_handle_irq(mmp2_handle_irq);
+
+ if (!parent) {
+ /* This is the main interrupt controller. */
+ irq_set_default_host(icu_data[0].domain);
+ set_handle_irq(mmp2_handle_irq);
+ }
+
max_icu_nr = 1;
return 0;
}
--
2.21.0
^ permalink raw reply related
* [PATCH 09/19] ARM: l2c: add definition for FWA in PL310 aux register
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
The PL310 also has a "Force write allocate" bits in the Auxiliary
Control Register.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
arch/arm/include/asm/hardware/cache-l2x0.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 32edfadb15935..a6d4ee86ba543 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -118,6 +118,8 @@
#define L310_AUX_CTRL_STORE_LIMITATION BIT(11) /* R2P0+ */
#define L310_AUX_CTRL_EXCLUSIVE_CACHE BIT(12)
#define L310_AUX_CTRL_ASSOCIATIVITY_16 BIT(16)
+#define L310_AUX_CTRL_FWA_SHIFT 23
+#define L310_AUX_CTRL_FWA_MASK (3 << 23)
#define L310_AUX_CTRL_CACHE_REPLACE_RR BIT(25) /* R2P0+ */
#define L310_AUX_CTRL_NS_LOCKDOWN BIT(26)
#define L310_AUX_CTRL_NS_INT_CTRL BIT(27)
--
2.21.0
^ permalink raw reply related
* [PATCH 10/19] ARM: mmp: don't select CACHE_TAUROS2 on all ARCH_MMP
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
MMP3 has a PJ4B with a Tauros 3 cache controller that uses CACHE_L2X0
instead, while CACHE_TAUROS2 is present on PJ4 and PJ1 (Mohawk) based
platforms only.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
arch/arm/mm/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index c54cd7ed90ba5..8dabce4507025 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -1045,7 +1045,7 @@ endif
config CACHE_TAUROS2
bool "Enable the Tauros2 L2 cache controller"
- depends on (ARCH_DOVE || ARCH_MMP || CPU_PJ4)
+ depends on (CPU_MOHAWK || CPU_PJ4)
default y
select OUTER_CACHE
help
--
2.21.0
^ permalink raw reply related
* [PATCH 11/19] ARM: mmp: map the PGU as well
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
The MMP2 and later includes a system control unit in this area. We'll need
that to initialize the secondary core on MMP3.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
arch/arm/mach-mmp/addr-map.h | 7 +++++++
arch/arm/mach-mmp/common.c | 15 +++++++++++++++
arch/arm/mach-mmp/common.h | 1 +
arch/arm/mach-mmp/mmp2-dt.c | 2 +-
4 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-mmp/addr-map.h b/arch/arm/mach-mmp/addr-map.h
index 25edf6a92276e..3dc2f0b0ecba5 100644
--- a/arch/arm/mach-mmp/addr-map.h
+++ b/arch/arm/mach-mmp/addr-map.h
@@ -20,6 +20,10 @@
#define AXI_VIRT_BASE IOMEM(0xfe200000)
#define AXI_PHYS_SIZE 0x00200000
+#define PGU_PHYS_BASE 0xe0000000
+#define PGU_VIRT_BASE IOMEM(0xfe400000)
+#define PGU_PHYS_SIZE 0x00100000
+
/* Static Memory Controller - Chip Select 0 and 1 */
#define SMC_CS0_PHYS_BASE 0x80000000
#define SMC_CS0_PHYS_SIZE 0x10000000
@@ -38,4 +42,7 @@
#define CIU_VIRT_BASE (AXI_VIRT_BASE + 0x82c00)
#define CIU_REG(x) (CIU_VIRT_BASE + (x))
+#define SCU_VIRT_BASE (PGU_VIRT_BASE)
+#define SCU_REG(x) (SCU_VIRT_BASE + (x))
+
#endif /* __ASM_MACH_ADDR_MAP_H */
diff --git a/arch/arm/mach-mmp/common.c b/arch/arm/mach-mmp/common.c
index 6684abc7708bd..2ee08c78e8bc9 100644
--- a/arch/arm/mach-mmp/common.c
+++ b/arch/arm/mach-mmp/common.c
@@ -36,6 +36,15 @@ static struct map_desc standard_io_desc[] __initdata = {
},
};
+static struct map_desc mmp2_io_desc[] __initdata = {
+ {
+ .pfn = __phys_to_pfn(PGU_PHYS_BASE),
+ .virtual = (unsigned long)PGU_VIRT_BASE,
+ .length = PGU_PHYS_SIZE,
+ .type = MT_DEVICE,
+ },
+};
+
void __init mmp_map_io(void)
{
iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
@@ -44,6 +53,12 @@ void __init mmp_map_io(void)
mmp_chip_id = __raw_readl(MMP_CHIPID);
}
+void __init mmp2_map_io(void)
+{
+ mmp_map_io();
+ iotable_init(mmp2_io_desc, ARRAY_SIZE(mmp2_io_desc));
+}
+
void mmp_restart(enum reboot_mode mode, const char *cmd)
{
soft_restart(0);
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index 483b8b6d3005a..ed56b3f15b45e 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -5,4 +5,5 @@
extern void mmp_timer_init(int irq, unsigned long rate);
extern void __init mmp_map_io(void);
+extern void __init mmp2_map_io(void);
extern void mmp_restart(enum reboot_mode, const char *);
diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c
index 305a9daba6d68..8eec881191f4b 100644
--- a/arch/arm/mach-mmp/mmp2-dt.c
+++ b/arch/arm/mach-mmp/mmp2-dt.c
@@ -33,7 +33,7 @@ static const char *const mmp2_dt_board_compat[] __initconst = {
};
DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
- .map_io = mmp_map_io,
+ .map_io = mmp2_map_io,
.init_time = mmp_init_time,
.dt_compat = mmp2_dt_board_compat,
MACHINE_END
--
2.21.0
^ permalink raw reply related
* [PATCH 12/19] ARM: mmp: DT: convert timer driver to use TIMER_OF_DECLARE
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
This makes things just a tiny bit simpler.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
arch/arm/mach-mmp/mmp-dt.c | 5 ++---
arch/arm/mach-mmp/mmp2-dt.c | 5 ++---
arch/arm/mach-mmp/time.c | 38 +++++++++++--------------------------
3 files changed, 15 insertions(+), 33 deletions(-)
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index 35559792d5cca..91214996acecc 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -9,14 +9,13 @@
#include <linux/irqchip.h>
#include <linux/of_platform.h>
#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/hardware/cache-tauros2.h>
#include "common.h"
-extern void __init mmp_dt_init_timer(void);
-
static const char *const pxa168_dt_board_compat[] __initconst = {
"mrvl,pxa168-aspenite",
NULL,
@@ -32,8 +31,8 @@ static void __init mmp_init_time(void)
#ifdef CONFIG_CACHE_TAUROS2
tauros2_init(0);
#endif
- mmp_dt_init_timer();
of_clk_init(NULL);
+ timer_probe();
}
DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c
index 8eec881191f4b..510c762ddc484 100644
--- a/arch/arm/mach-mmp/mmp2-dt.c
+++ b/arch/arm/mach-mmp/mmp2-dt.c
@@ -10,21 +10,20 @@
#include <linux/irqchip.h>
#include <linux/of_platform.h>
#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/hardware/cache-tauros2.h>
#include "common.h"
-extern void __init mmp_dt_init_timer(void);
-
static void __init mmp_init_time(void)
{
#ifdef CONFIG_CACHE_TAUROS2
tauros2_init(0);
#endif
of_clk_init(NULL);
- mmp_dt_init_timer();
+ timer_probe();
}
static const char *const mmp2_dt_board_compat[] __initconst = {
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 483df32583be6..3f6fd0be00512 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -195,30 +195,17 @@ void __init mmp_timer_init(int irq, unsigned long rate)
clockevents_config_and_register(&ckevt, rate, MIN_DELTA, MAX_DELTA);
}
-#ifdef CONFIG_OF
-static const struct of_device_id mmp_timer_dt_ids[] = {
- { .compatible = "mrvl,mmp-timer", },
- {}
-};
-
-void __init mmp_dt_init_timer(void)
+static int __init mmp_dt_init_timer(struct device_node *np)
{
- struct device_node *np;
struct clk *clk;
int irq, ret;
unsigned long rate;
- np = of_find_matching_node(NULL, mmp_timer_dt_ids);
- if (!np) {
- ret = -ENODEV;
- goto out;
- }
-
clk = of_clk_get(np, 0);
if (!IS_ERR(clk)) {
ret = clk_prepare_enable(clk);
if (ret)
- goto out;
+ return ret;
rate = clk_get_rate(clk) / 2;
} else if (cpu_is_pj4()) {
rate = 6500000;
@@ -227,18 +214,15 @@ void __init mmp_dt_init_timer(void)
}
irq = irq_of_parse_and_map(np, 0);
- if (!irq) {
- ret = -EINVAL;
- goto out;
- }
+ if (!irq)
+ return -EINVAL;
+
mmp_timer_base = of_iomap(np, 0);
- if (!mmp_timer_base) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!mmp_timer_base)
+ return -ENOMEM;
+
mmp_timer_init(irq, rate);
- return;
-out:
- pr_err("Failed to get timer from device tree with error:%d\n", ret);
+ return 0;
}
-#endif
+
+TIMER_OF_DECLARE(mmp_timer, "mrvl,mmp-timer", mmp_dt_init_timer);
--
2.21.0
^ permalink raw reply related
* [PATCH 13/19] ARM: mmp: define MMP_CHIPID by the means of CIU_REG()
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
A rather trivial cosmetic improvement.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
arch/arm/mach-mmp/common.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mach-mmp/common.c b/arch/arm/mach-mmp/common.c
index 2ee08c78e8bc9..24c689a01ecb7 100644
--- a/arch/arm/mach-mmp/common.c
+++ b/arch/arm/mach-mmp/common.c
@@ -17,7 +17,7 @@
#include "common.h"
-#define MMP_CHIPID (AXI_VIRT_BASE + 0x82c00)
+#define MMP_CHIPID CIU_REG(0x00)
unsigned int mmp_chip_id;
EXPORT_SYMBOL(mmp_chip_id);
--
2.21.0
^ permalink raw reply related
* [PATCH 14/19] ARM: mmp: add support for MMP3 SoC
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
Similar to MMP2, which this patch is based on. Known differencies from MMP2
are:
* Two PJ4B cores instead of one PJ4
* Tauros 3 L2 cache controller instead of Tauros 2
* A GIC interrupt controller optionally used instead of the MMP one
* A TWD local timer
* Different USB2 PHY
* A USB3 SS controller
* More interrupt muxes
Hard to tell what else is different, because documentation is not
available.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
arch/arm/mach-mmp/Kconfig | 22 ++++++++++++++++++++--
arch/arm/mach-mmp/Makefile | 1 +
arch/arm/mach-mmp/cputype.h | 27 +++++++++++++++++++++++++++
arch/arm/mach-mmp/mmp3.c | 29 +++++++++++++++++++++++++++++
arch/arm/mach-mmp/time.c | 3 ++-
drivers/clk/mmp/Makefile | 1 +
6 files changed, 80 insertions(+), 3 deletions(-)
create mode 100644 arch/arm/mach-mmp/mmp3.c
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index 0440109e973b9..b58a03b18bdef 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -1,13 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig ARCH_MMP
- bool "Marvell PXA168/910/MMP2"
+ bool "Marvell PXA168/910/MMP2/MMP3"
depends on ARCH_MULTI_V5 || ARCH_MULTI_V7
select GPIO_PXA
select GPIOLIB
select PINCTRL
select PLAT_PXA
help
- Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
+ Support for Marvell's PXA168/PXA910(MMP), MMP2, and MMP3 processor lines.
if ARCH_MMP
@@ -129,6 +129,24 @@ config MACH_MMP2_DT
Include support for Marvell MMP2 based platforms using
the device tree.
+config MACH_MMP3_DT
+ bool "Support MMP3 (ARMv7) platforms"
+ depends on ARCH_MULTI_V7
+ select ARM_GIC
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if SMP
+ select CACHE_L2X0
+ select PINCTRL
+ select PINCTRL_SINGLE
+ select ARCH_HAS_RESET_CONTROLLER
+ select CPU_PJ4B
+ select PM_GENERIC_DOMAINS if PM
+ select PM_GENERIC_DOMAINS_OF if PM && OF
+ help
+ Say 'Y' here if you want to include support for platforms
+ with Marvell MMP3 processor, also known as PXA2128 or
+ Armada 620.
+
endmenu
config CPU_PXA168
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 8f267c7bc6e86..322c1c97dc900 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -34,5 +34,6 @@ obj-$(CONFIG_MACH_FLINT) += flint.o
obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
obj-$(CONFIG_MACH_MMP_DT) += mmp-dt.o
obj-$(CONFIG_MACH_MMP2_DT) += mmp2-dt.o
+obj-$(CONFIG_MACH_MMP3_DT) += mmp3.o
obj-$(CONFIG_MACH_TETON_BGA) += teton_bga.o
obj-$(CONFIG_MACH_GPLUGD) += gplugd.o
diff --git a/arch/arm/mach-mmp/cputype.h b/arch/arm/mach-mmp/cputype.h
index a96abcf521b4b..c3ec88983e940 100644
--- a/arch/arm/mach-mmp/cputype.h
+++ b/arch/arm/mach-mmp/cputype.h
@@ -18,6 +18,8 @@
* MMP2 Z0 0x560f5811 0x00F00410
* MMP2 Z1 0x560f5811 0x00E00410
* MMP2 A0 0x560f5811 0x00A0A610
+ * MMP3 A0 0x562f5842 0x00A02128
+ * MMP3 B0 0x562f5842 0x00B02128
*/
extern unsigned int mmp_chip_id;
@@ -55,4 +57,29 @@ static inline int cpu_is_mmp2(void)
#define cpu_is_mmp2() (0)
#endif
+#ifdef CONFIG_MACH_MMP3_DT
+static inline int cpu_is_mmp3(void)
+{
+ return (((read_cpuid_id() >> 8) & 0xff) == 0x58) &&
+ ((mmp_chip_id & 0xffff) == 0x2128);
+}
+
+static inline int cpu_is_mmp3_a0(void)
+{
+ return (cpu_is_mmp3() &&
+ ((mmp_chip_id & 0x00ff0000) == 0x00a00000));
+}
+
+static inline int cpu_is_mmp3_b0(void)
+{
+ return (cpu_is_mmp3() &&
+ ((mmp_chip_id & 0x00ff0000) == 0x00b00000));
+}
+
+#else
+#define cpu_is_mmp3() (0)
+#define cpu_is_mmp3_a0() (0)
+#define cpu_is_mmp3_b0() (0)
+#endif
+
#endif /* __ASM_MACH_CPUTYPE_H */
diff --git a/arch/arm/mach-mmp/mmp3.c b/arch/arm/mach-mmp/mmp3.c
new file mode 100644
index 0000000000000..b0e86964f302a
--- /dev/null
+++ b/arch/arm/mach-mmp/mmp3.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Marvell MMP3 aka PXA2128 aka 88AP2128 support
+ *
+ * Copyright (C) 2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/of_platform.h>
+#include <linux/clk-provider.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include "common.h"
+
+static const char *const mmp3_dt_board_compat[] __initconst = {
+ "marvell,mmp3",
+ NULL,
+};
+
+DT_MACHINE_START(MMP2_DT, "Marvell MMP3")
+ .map_io = mmp2_map_io,
+ .dt_compat = mmp3_dt_board_compat,
+ .l2c_aux_val = 1 << L310_AUX_CTRL_FWA_SHIFT |
+ L310_AUX_CTRL_DATA_PREFETCH |
+ L310_AUX_CTRL_INSTR_PREFETCH,
+ .l2c_aux_mask = 0xc20fffff,
+MACHINE_END
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 3f6fd0be00512..8f4cacbf640e9 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -155,7 +155,8 @@ static void __init timer_config(void)
__raw_writel(0x0, mmp_timer_base + TMR_CER); /* disable */
- ccr &= (cpu_is_mmp2()) ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
+ ccr &= (cpu_is_mmp2() || cpu_is_mmp3()) ?
+ (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
(TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3));
__raw_writel(ccr, mmp_timer_base + TMR_CCR);
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 7bc7ac69391e3..deb069a4e4215 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_RESET_CONTROLLER) += reset.o
obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o
obj-$(CONFIG_MACH_MMP2_DT) += clk-of-mmp2.o
+obj-$(CONFIG_MACH_MMP3_DT) += clk-of-mmp2.o
obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
--
2.21.0
^ permalink raw reply related
* [PATCH 15/19] ARM: mmp: add SMP support
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
Used to bring up the second core on MMP3.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
arch/arm/mach-mmp/Makefile | 3 +++
arch/arm/mach-mmp/platsmp.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 35 insertions(+)
create mode 100644 arch/arm/mach-mmp/platsmp.c
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 322c1c97dc900..7b3a7f979eece 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -22,6 +22,9 @@ ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_CPU_PXA910) += pm-pxa910.o
obj-$(CONFIG_CPU_MMP2) += pm-mmp2.o
endif
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_MACH_MMP3_DT) += platsmp.o
+endif
# board support
obj-$(CONFIG_MACH_ASPENITE) += aspenite.o
diff --git a/arch/arm/mach-mmp/platsmp.c b/arch/arm/mach-mmp/platsmp.c
new file mode 100644
index 0000000000000..255df640b5bc1
--- /dev/null
+++ b/arch/arm/mach-mmp/platsmp.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+#include <linux/io.h>
+#include <asm/smp_scu.h>
+#include <asm/smp.h>
+#include "addr-map.h"
+
+#define SW_BRANCH_VIRT_ADDR CIU_REG(0x24)
+
+static int mmp3_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ /*
+ * Apparently, the boot ROM on the second core spins on this
+ * register becoming non-zero and then jumps to the address written
+ * there. No IPIs involved.
+ */
+ __raw_writel(virt_to_phys(secondary_startup), SW_BRANCH_VIRT_ADDR);
+ return 0;
+}
+
+static void mmp3_smp_prepare_cpus(unsigned int max_cpus)
+{
+ scu_enable(SCU_VIRT_BASE);
+}
+
+static const struct smp_operations mmp3_smp_ops __initconst = {
+ .smp_prepare_cpus = mmp3_smp_prepare_cpus,
+ .smp_boot_secondary = mmp3_boot_secondary,
+};
+CPU_METHOD_OF_DECLARE(mmp3_smp, "marvell,mmp3-smp", &mmp3_smp_ops);
--
2.21.0
^ permalink raw reply related
* [PATCH 16/19] ARM: mmp: move cputype.h to include/linux/soc/
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
Let's move cputype.h away from mach-mmp/ so that the drivers outside that
directory are able to tell the precise silicon revision. The MMP3 USB OTG
PHY driver needs this.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
MAINTAINERS | 1 +
arch/arm/mach-mmp/common.c | 2 +-
arch/arm/mach-mmp/devices.c | 2 +-
arch/arm/mach-mmp/mmp2.c | 2 +-
arch/arm/mach-mmp/pm-mmp2.c | 2 +-
arch/arm/mach-mmp/pm-pxa910.c | 2 +-
arch/arm/mach-mmp/pxa168.c | 2 +-
arch/arm/mach-mmp/pxa910.c | 2 +-
arch/arm/mach-mmp/time.c | 2 +-
{arch/arm/mach-mmp => include/linux/soc/mmp}/cputype.h | 0
10 files changed, 9 insertions(+), 8 deletions(-)
rename {arch/arm/mach-mmp => include/linux/soc/mmp}/cputype.h (100%)
diff --git a/MAINTAINERS b/MAINTAINERS
index a2c343ee3b2ca..fb2ceb265a8c3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10788,6 +10788,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Odd Fixes
F: arch/arm/boot/dts/mmp*
F: arch/arm/mach-mmp/
+F: linux/soc/mmp/
MMU GATHER AND TLB INVALIDATION
M: Will Deacon <will@kernel.org>
diff --git a/arch/arm/mach-mmp/common.c b/arch/arm/mach-mmp/common.c
index 24c689a01ecb7..e94349d4726ca 100644
--- a/arch/arm/mach-mmp/common.c
+++ b/arch/arm/mach-mmp/common.c
@@ -13,7 +13,7 @@
#include <asm/mach/map.h>
#include <asm/system_misc.h>
#include "addr-map.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
#include "common.h"
diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c
index 130c1a603ba29..18bee66a671ff 100644
--- a/arch/arm/mach-mmp/devices.c
+++ b/arch/arm/mach-mmp/devices.c
@@ -11,7 +11,7 @@
#include <asm/irq.h>
#include "irqs.h"
#include "devices.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
#include "regs-usb.h"
int __init pxa_register_device(struct pxa_device_desc *desc,
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index 18ea3e1a26e69..bbc4c2274de3a 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -20,7 +20,7 @@
#include <asm/mach/time.h>
#include "addr-map.h"
#include "regs-apbc.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
#include "irqs.h"
#include "mfp.h"
#include "devices.h"
diff --git a/arch/arm/mach-mmp/pm-mmp2.c b/arch/arm/mach-mmp/pm-mmp2.c
index 2923dd5732a62..2d86381e152d6 100644
--- a/arch/arm/mach-mmp/pm-mmp2.c
+++ b/arch/arm/mach-mmp/pm-mmp2.c
@@ -17,7 +17,7 @@
#include <linux/interrupt.h>
#include <asm/mach-types.h>
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
#include "addr-map.h"
#include "pm-mmp2.h"
#include "regs-icu.h"
diff --git a/arch/arm/mach-mmp/pm-pxa910.c b/arch/arm/mach-mmp/pm-pxa910.c
index 58535ce206dc5..69ebe18ff209f 100644
--- a/arch/arm/mach-mmp/pm-pxa910.c
+++ b/arch/arm/mach-mmp/pm-pxa910.c
@@ -18,7 +18,7 @@
#include <asm/mach-types.h>
#include <asm/outercache.h>
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
#include "addr-map.h"
#include "pm-pxa910.h"
#include "regs-icu.h"
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 6e02774889679..b642e900727a5 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -21,7 +21,7 @@
#include "addr-map.h"
#include "clock.h"
#include "common.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
#include "devices.h"
#include "irqs.h"
#include "mfp.h"
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index cba31c758dea6..b19a069d9fabe 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -18,7 +18,7 @@
#include <asm/mach/time.h>
#include "addr-map.h"
#include "regs-apbc.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
#include "irqs.h"
#include "mfp.h"
#include "devices.h"
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 8f4cacbf640e9..110dcb3314d13 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -33,7 +33,7 @@
#include "regs-timers.h"
#include "regs-apbc.h"
#include "irqs.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
#include "clock.h"
#define TIMERS_VIRT_BASE TIMERS1_VIRT_BASE
diff --git a/arch/arm/mach-mmp/cputype.h b/include/linux/soc/mmp/cputype.h
similarity index 100%
rename from arch/arm/mach-mmp/cputype.h
rename to include/linux/soc/mmp/cputype.h
--
2.21.0
^ permalink raw reply related
* [PATCH 17/19] ARM: mmp: remove MMP3 USB PHY registers from regs-usb.h
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
Nothing in mach-mmp/ uses them and they belong to the PHY driver.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
arch/arm/mach-mmp/regs-usb.h | 94 ------------------------------------
1 file changed, 94 deletions(-)
diff --git a/arch/arm/mach-mmp/regs-usb.h b/arch/arm/mach-mmp/regs-usb.h
index d9f08c1601542..ed0d1aa0ad6c9 100644
--- a/arch/arm/mach-mmp/regs-usb.h
+++ b/arch/arm/mach-mmp/regs-usb.h
@@ -121,100 +121,6 @@
#define UTMI_OTG_ADDON_OTG_ON (1 << 0)
-/* For MMP3 USB Phy */
-#define USB2_PLL_REG0 0x4
-#define USB2_PLL_REG1 0x8
-#define USB2_TX_REG0 0x10
-#define USB2_TX_REG1 0x14
-#define USB2_TX_REG2 0x18
-#define USB2_RX_REG0 0x20
-#define USB2_RX_REG1 0x24
-#define USB2_RX_REG2 0x28
-#define USB2_ANA_REG0 0x30
-#define USB2_ANA_REG1 0x34
-#define USB2_ANA_REG2 0x38
-#define USB2_DIG_REG0 0x3C
-#define USB2_DIG_REG1 0x40
-#define USB2_DIG_REG2 0x44
-#define USB2_DIG_REG3 0x48
-#define USB2_TEST_REG0 0x4C
-#define USB2_TEST_REG1 0x50
-#define USB2_TEST_REG2 0x54
-#define USB2_CHARGER_REG0 0x58
-#define USB2_OTG_REG0 0x5C
-#define USB2_PHY_MON0 0x60
-#define USB2_RESETVE_REG0 0x64
-#define USB2_ICID_REG0 0x78
-#define USB2_ICID_REG1 0x7C
-
-/* USB2_PLL_REG0 */
-/* This is for Ax stepping */
-#define USB2_PLL_FBDIV_SHIFT_MMP3 0
-#define USB2_PLL_FBDIV_MASK_MMP3 (0xFF << 0)
-
-#define USB2_PLL_REFDIV_SHIFT_MMP3 8
-#define USB2_PLL_REFDIV_MASK_MMP3 (0xF << 8)
-
-#define USB2_PLL_VDD12_SHIFT_MMP3 12
-#define USB2_PLL_VDD18_SHIFT_MMP3 14
-
-/* This is for B0 stepping */
-#define USB2_PLL_FBDIV_SHIFT_MMP3_B0 0
-#define USB2_PLL_REFDIV_SHIFT_MMP3_B0 9
-#define USB2_PLL_VDD18_SHIFT_MMP3_B0 14
-#define USB2_PLL_FBDIV_MASK_MMP3_B0 0x01FF
-#define USB2_PLL_REFDIV_MASK_MMP3_B0 0x3E00
-
-#define USB2_PLL_CAL12_SHIFT_MMP3 0
-#define USB2_PLL_CALI12_MASK_MMP3 (0x3 << 0)
-
-#define USB2_PLL_VCOCAL_START_SHIFT_MMP3 2
-
-#define USB2_PLL_KVCO_SHIFT_MMP3 4
-#define USB2_PLL_KVCO_MASK_MMP3 (0x7<<4)
-
-#define USB2_PLL_ICP_SHIFT_MMP3 8
-#define USB2_PLL_ICP_MASK_MMP3 (0x7<<8)
-
-#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3 12
-
-#define USB2_PLL_PU_PLL_SHIFT_MMP3 13
-#define USB2_PLL_PU_PLL_MASK (0x1 << 13)
-
-#define USB2_PLL_READY_MASK_MMP3 (0x1 << 15)
-
-/* USB2_TX_REG0 */
-#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3 8
-#define USB2_TX_IMPCAL_VTH_MASK_MMP3 (0x7 << 8)
-
-#define USB2_TX_RCAL_START_SHIFT_MMP3 13
-
-/* USB2_TX_REG1 */
-#define USB2_TX_CK60_PHSEL_SHIFT_MMP3 0
-#define USB2_TX_CK60_PHSEL_MASK_MMP3 (0xf << 0)
-
-#define USB2_TX_AMP_SHIFT_MMP3 4
-#define USB2_TX_AMP_MASK_MMP3 (0x7 << 4)
-
-#define USB2_TX_VDD12_SHIFT_MMP3 8
-#define USB2_TX_VDD12_MASK_MMP3 (0x3 << 8)
-
-/* USB2_TX_REG2 */
-#define USB2_TX_DRV_SLEWRATE_SHIFT 10
-
-/* USB2_RX_REG0 */
-#define USB2_RX_SQ_THRESH_SHIFT_MMP3 4
-#define USB2_RX_SQ_THRESH_MASK_MMP3 (0xf << 4)
-
-#define USB2_RX_SQ_LENGTH_SHIFT_MMP3 10
-#define USB2_RX_SQ_LENGTH_MASK_MMP3 (0x3 << 10)
-
-/* USB2_ANA_REG1*/
-#define USB2_ANA_PU_ANA_SHIFT_MMP3 14
-
-/* USB2_OTG_REG0 */
-#define USB2_OTG_PU_OTG_SHIFT_MMP3 3
-
/* fsic registers */
#define FSIC_MISC 0x4
#define FSIC_INT 0x28
--
2.21.0
^ permalink raw reply related
* [PATCH 18/19] phy: phy-mmp3-usb: add a new driver
From: Lubomir Rintel @ 2019-08-09 9:31 UTC (permalink / raw)
To: Olof Johansson
Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
Marc Zyngier, Kishon Vijay Abraham I, Russell King,
Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>
This is the USB2 PHY as found on the Marvell MMP3 SoC. Based on Marvell GPL
release.
While at that, also add a MAINTAINERS entry including the other MMP PHY
driver.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
MAINTAINERS | 7 +
drivers/phy/marvell/Kconfig | 11 ++
drivers/phy/marvell/Makefile | 1 +
drivers/phy/marvell/phy-mmp3-usb.c | 291 +++++++++++++++++++++++++++++
4 files changed, 310 insertions(+)
create mode 100644 drivers/phy/marvell/phy-mmp3-usb.c
diff --git a/MAINTAINERS b/MAINTAINERS
index fb2ceb265a8c3..fb7e8edfc3d66 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10790,6 +10790,13 @@ F: arch/arm/boot/dts/mmp*
F: arch/arm/mach-mmp/
F: linux/soc/mmp/
+MMP USB PHY DRIVERS
+R: Lubomir Rintel <lkundrak@v3.sk>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: drivers/phy/marvell/phy-mmp3-usb.c
+F: drivers/phy/marvell/phy-pxa-usb.c
+
MMU GATHER AND TLB INVALIDATION
M: Will Deacon <will@kernel.org>
M: "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig
index 0e1642419c0bf..d33ef35b3e51b 100644
--- a/drivers/phy/marvell/Kconfig
+++ b/drivers/phy/marvell/Kconfig
@@ -102,3 +102,14 @@ config PHY_PXA_USB
The PHY driver will be used by Marvell udc/ehci/otg driver.
To compile this driver as a module, choose M here.
+
+config PHY_MMP3_USB
+ tristate "Marvell MMP3 USB PHY Driver"
+ depends on MACH_MMP3_DT || COMPILE_TEST
+ select GENERIC_PHY
+ help
+ Enable this to support Marvell MMP3 USB PHY driver for Marvell
+ SoC. This driver will do the PHY initialization and shutdown.
+ The PHY driver will be used by Marvell udc/ehci/otg driver.
+
+ To compile this driver as a module, choose M here.
diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile
index 434eb9ca6cc3f..5a106b1549f41 100644
--- a/drivers/phy/marvell/Makefile
+++ b/drivers/phy/marvell/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
+obj-$(CONFIG_PHY_MMP3_USB) += phy-mmp3-usb.o
obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY) += phy-mvebu-a3700-comphy.o
obj-$(CONFIG_PHY_MVEBU_A3700_UTMI) += phy-mvebu-a3700-utmi.o
obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY) += phy-armada38x-comphy.o
diff --git a/drivers/phy/marvell/phy-mmp3-usb.c b/drivers/phy/marvell/phy-mmp3-usb.c
new file mode 100644
index 0000000000000..499869595a582
--- /dev/null
+++ b/drivers/phy/marvell/phy-mmp3-usb.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Copyright (C) 2018,2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/soc/mmp/cputype.h>
+
+#define USB2_PLL_REG0 0x4
+#define USB2_PLL_REG1 0x8
+#define USB2_TX_REG0 0x10
+#define USB2_TX_REG1 0x14
+#define USB2_TX_REG2 0x18
+#define USB2_RX_REG0 0x20
+#define USB2_RX_REG1 0x24
+#define USB2_RX_REG2 0x28
+#define USB2_ANA_REG0 0x30
+#define USB2_ANA_REG1 0x34
+#define USB2_ANA_REG2 0x38
+#define USB2_DIG_REG0 0x3C
+#define USB2_DIG_REG1 0x40
+#define USB2_DIG_REG2 0x44
+#define USB2_DIG_REG3 0x48
+#define USB2_TEST_REG0 0x4C
+#define USB2_TEST_REG1 0x50
+#define USB2_TEST_REG2 0x54
+#define USB2_CHARGER_REG0 0x58
+#define USB2_OTG_REG0 0x5C
+#define USB2_PHY_MON0 0x60
+#define USB2_RESETVE_REG0 0x64
+#define USB2_ICID_REG0 0x78
+#define USB2_ICID_REG1 0x7C
+
+/* USB2_PLL_REG0 */
+
+/* This is for Ax stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3 0
+#define USB2_PLL_FBDIV_MASK_MMP3 (0xFF << 0)
+
+#define USB2_PLL_REFDIV_SHIFT_MMP3 8
+#define USB2_PLL_REFDIV_MASK_MMP3 (0xF << 8)
+
+#define USB2_PLL_VDD12_SHIFT_MMP3 12
+#define USB2_PLL_VDD18_SHIFT_MMP3 14
+
+/* This is for B0 stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3_B0 0
+#define USB2_PLL_REFDIV_SHIFT_MMP3_B0 9
+#define USB2_PLL_VDD18_SHIFT_MMP3_B0 14
+#define USB2_PLL_FBDIV_MASK_MMP3_B0 0x01FF
+#define USB2_PLL_REFDIV_MASK_MMP3_B0 0x3E00
+
+#define USB2_PLL_CAL12_SHIFT_MMP3 0
+#define USB2_PLL_CALI12_MASK_MMP3 (0x3 << 0)
+
+#define USB2_PLL_VCOCAL_START_SHIFT_MMP3 2
+
+#define USB2_PLL_KVCO_SHIFT_MMP3 4
+#define USB2_PLL_KVCO_MASK_MMP3 (0x7<<4)
+
+#define USB2_PLL_ICP_SHIFT_MMP3 8
+#define USB2_PLL_ICP_MASK_MMP3 (0x7<<8)
+
+#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3 12
+
+#define USB2_PLL_PU_PLL_SHIFT_MMP3 13
+#define USB2_PLL_PU_PLL_MASK (0x1 << 13)
+
+#define USB2_PLL_READY_MASK_MMP3 (0x1 << 15)
+
+/* USB2_TX_REG0 */
+#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3 8
+#define USB2_TX_IMPCAL_VTH_MASK_MMP3 (0x7 << 8)
+
+#define USB2_TX_RCAL_START_SHIFT_MMP3 13
+
+/* USB2_TX_REG1 */
+#define USB2_TX_CK60_PHSEL_SHIFT_MMP3 0
+#define USB2_TX_CK60_PHSEL_MASK_MMP3 (0xf << 0)
+
+#define USB2_TX_AMP_SHIFT_MMP3 4
+#define USB2_TX_AMP_MASK_MMP3 (0x7 << 4)
+
+#define USB2_TX_VDD12_SHIFT_MMP3 8
+#define USB2_TX_VDD12_MASK_MMP3 (0x3 << 8)
+
+/* USB2_TX_REG2 */
+#define USB2_TX_DRV_SLEWRATE_SHIFT 10
+
+/* USB2_RX_REG0 */
+#define USB2_RX_SQ_THRESH_SHIFT_MMP3 4
+#define USB2_RX_SQ_THRESH_MASK_MMP3 (0xf << 4)
+
+#define USB2_RX_SQ_LENGTH_SHIFT_MMP3 10
+#define USB2_RX_SQ_LENGTH_MASK_MMP3 (0x3 << 10)
+
+/* USB2_ANA_REG1*/
+#define USB2_ANA_PU_ANA_SHIFT_MMP3 14
+
+/* USB2_OTG_REG0 */
+#define USB2_OTG_PU_OTG_SHIFT_MMP3 3
+
+struct mmp3_usb_phy {
+ struct phy *phy;
+ void __iomem *base;
+};
+
+static unsigned int u2o_get(void __iomem *base, unsigned int offset)
+{
+ return readl_relaxed(base + offset);
+}
+
+static void u2o_set(void __iomem *base, unsigned int offset,
+ unsigned int value)
+{
+ u32 reg;
+
+ reg = readl_relaxed(base + offset);
+ reg |= value;
+ writel_relaxed(reg, base + offset);
+ readl_relaxed(base + offset);
+}
+
+static void u2o_clear(void __iomem *base, unsigned int offset,
+ unsigned int value)
+{
+ u32 reg;
+
+ reg = readl_relaxed(base + offset);
+ reg &= ~value;
+ writel_relaxed(reg, base + offset);
+ readl_relaxed(base + offset);
+}
+
+static int mmp3_usb_phy_init(struct phy *phy)
+{
+ struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
+ void __iomem *base = mmp3_usb_phy->base;
+
+ if (cpu_is_mmp3_a0()) {
+ u2o_clear(base, USB2_PLL_REG0, (USB2_PLL_FBDIV_MASK_MMP3
+ | USB2_PLL_REFDIV_MASK_MMP3));
+ u2o_set(base, USB2_PLL_REG0,
+ 0xd << USB2_PLL_REFDIV_SHIFT_MMP3
+ | 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3);
+ } else if (cpu_is_mmp3_b0()) {
+ u2o_clear(base, USB2_PLL_REG0, USB2_PLL_REFDIV_MASK_MMP3_B0
+ | USB2_PLL_FBDIV_MASK_MMP3_B0);
+ u2o_set(base, USB2_PLL_REG0,
+ 0xd << USB2_PLL_REFDIV_SHIFT_MMP3_B0
+ | 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3_B0);
+ } else {
+ dev_err(&phy->dev, "unsupported silicon revision\n");
+ return -ENODEV;
+ }
+
+ u2o_clear(base, USB2_PLL_REG1, USB2_PLL_PU_PLL_MASK
+ | USB2_PLL_ICP_MASK_MMP3
+ | USB2_PLL_KVCO_MASK_MMP3
+ | USB2_PLL_CALI12_MASK_MMP3);
+ u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_PU_PLL_SHIFT_MMP3
+ | 1 << USB2_PLL_LOCK_BYPASS_SHIFT_MMP3
+ | 3 << USB2_PLL_ICP_SHIFT_MMP3
+ | 3 << USB2_PLL_KVCO_SHIFT_MMP3
+ | 3 << USB2_PLL_CAL12_SHIFT_MMP3);
+
+ u2o_clear(base, USB2_TX_REG0, USB2_TX_IMPCAL_VTH_MASK_MMP3);
+ u2o_set(base, USB2_TX_REG0, 2 << USB2_TX_IMPCAL_VTH_SHIFT_MMP3);
+
+ u2o_clear(base, USB2_TX_REG1, USB2_TX_VDD12_MASK_MMP3
+ | USB2_TX_AMP_MASK_MMP3
+ | USB2_TX_CK60_PHSEL_MASK_MMP3);
+ u2o_set(base, USB2_TX_REG1, 3 << USB2_TX_VDD12_SHIFT_MMP3
+ | 4 << USB2_TX_AMP_SHIFT_MMP3
+ | 4 << USB2_TX_CK60_PHSEL_SHIFT_MMP3);
+
+ u2o_clear(base, USB2_TX_REG2, 3 << USB2_TX_DRV_SLEWRATE_SHIFT);
+ u2o_set(base, USB2_TX_REG2, 2 << USB2_TX_DRV_SLEWRATE_SHIFT);
+
+ u2o_clear(base, USB2_RX_REG0, USB2_RX_SQ_THRESH_MASK_MMP3);
+ u2o_set(base, USB2_RX_REG0, 0xa << USB2_RX_SQ_THRESH_SHIFT_MMP3);
+
+ u2o_set(base, USB2_ANA_REG1, 0x1 << USB2_ANA_PU_ANA_SHIFT_MMP3);
+
+ u2o_set(base, USB2_OTG_REG0, 0x1 << USB2_OTG_PU_OTG_SHIFT_MMP3);
+
+ return 0;
+}
+
+static int mmp3_usb_phy_calibrate(struct phy *phy)
+{
+ struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
+ void __iomem *base = mmp3_usb_phy->base;
+ int loops;
+
+ /*
+ * PLL VCO and TX Impedance Calibration Timing:
+ *
+ * _____________________________________
+ * PU __________|
+ * _____________________________
+ * VCOCAL START _________|
+ * ___
+ * REG_RCAL_START ________________| |________|_______
+ * | 200us | 400us | 40| 400us | USB PHY READY
+ */
+
+ udelay(200);
+ u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_VCOCAL_START_SHIFT_MMP3);
+ udelay(400);
+ u2o_set(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
+ udelay(40);
+ u2o_clear(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
+ udelay(400);
+
+ loops = 0;
+ while ((u2o_get(base, USB2_PLL_REG1) & USB2_PLL_READY_MASK_MMP3) == 0) {
+ mdelay(1);
+ loops++;
+ if (loops > 100) {
+ dev_err(&phy->dev, "PLL_READY not set after 100mS.\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static const struct phy_ops mmp3_usb_phy_ops = {
+ .init = mmp3_usb_phy_init,
+ .calibrate = mmp3_usb_phy_calibrate,
+ .owner = THIS_MODULE,
+};
+
+static const struct of_device_id mmp3_usb_phy_of_match[] = {
+ { .compatible = "marvell,mmp3-usb-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mmp3_usb_phy_of_match);
+
+static int mmp3_usb_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *resource;
+ struct mmp3_usb_phy *mmp3_usb_phy;
+ struct phy_provider *provider;
+
+ mmp3_usb_phy = devm_kzalloc(dev, sizeof(*mmp3_usb_phy), GFP_KERNEL);
+ if (!mmp3_usb_phy)
+ return -ENOMEM;
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mmp3_usb_phy->base = devm_ioremap_resource(dev, resource);
+ if (IS_ERR(mmp3_usb_phy->base)) {
+ dev_err(dev, "failed to remap PHY regs\n");
+ return PTR_ERR(mmp3_usb_phy->base);
+ }
+
+ mmp3_usb_phy->phy = devm_phy_create(dev, NULL, &mmp3_usb_phy_ops);
+ if (IS_ERR(mmp3_usb_phy->phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(mmp3_usb_phy->phy);
+ }
+
+ phy_set_drvdata(mmp3_usb_phy->phy, mmp3_usb_phy);
+ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(provider)) {
+ dev_err(dev, "failed to register PHY provider\n");
+ return PTR_ERR(provider);
+ }
+
+ return 0;
+}
+
+static struct platform_driver mmp3_usb_phy_driver = {
+ .probe = mmp3_usb_phy_probe,
+ .driver = {
+ .name = "mmp3-usb-phy",
+ .of_match_table = mmp3_usb_phy_of_match,
+ },
+};
+module_platform_driver(mmp3_usb_phy_driver);
+
+MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+MODULE_DESCRIPTION("Marvell MMP3 USB PHY Driver");
+MODULE_LICENSE("GPL v2");
--
2.21.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox