* [PATCH v6 1/3] drm/panel: simple: Add ability to override typical timing
From: Douglas Anderson @ 2019-07-11 20:34 UTC (permalink / raw)
To: Thierry Reding, Heiko Stuebner, Sean Paul
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Eric Anholt,
David Airlie, Sam Ravnborg, Jeffy Chen, Doug Anderson,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Boris Brezillon,
Laurent Pinchart, Daniel Vetter, Enric Balletbo i Serra,
Stéphane Marchesin, Ezequiel Garcia,
mka-F7+t8E8rja9g9hUCZPvPmw
In-Reply-To: <20190711203455.125667-1-dianders-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
From: Sean Paul <seanpaul@chromium.org>
This patch adds the ability to override the typical display timing for a
given panel. This is useful for devices which have timing constraints
that do not apply across the entire display driver (eg: to avoid
crosstalk between panel and digitizer on certain laptops). The rules are
as follows:
- panel must not specify fixed mode (since the override mode will
either be the same as the fixed mode, or we'll be unable to
check the bounds of the overried)
- panel must specify at least one display_timing range which will be
used to ensure the override mode fits within its bounds
Changes in v2:
- Parse the full display-timings node (using the native-mode) (Rob)
Changes in v3:
- No longer parse display-timings subnode, use panel-timing (Rob)
Changes in v4:
- Don't add mode from timing if override was specified (Thierry)
- Add warning if timing and fixed mode was specified (Thierry)
- Don't add fixed mode if timing was specified (Thierry)
- Refactor/rename a bit to avoid extra indentation from "if" tests
- i should be unsigned (Thierry)
- Add annoying WARN_ONs for some cases (Thierry)
- Simplify 'No display_timing found' handling (Thierry)
- Rename to panel_simple_parse_override_mode() (Thierry)
Changes in v5:
- Added Heiko's Tested-by
Changes in v6:
- Rebased to drm-misc next
- Added tags
Cc: Doug Anderson <dianders@chromium.org>
Cc: Eric Anholt <eric@anholt.net>
Cc: Heiko Stuebner <heiko@sntech.de>
Cc: Jeffy Chen <jeffy.chen@rock-chips.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Stéphane Marchesin <marcheu@chromium.org>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: devicetree@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Acked-by: Thierry Reding <thierry.reding@gmail.com>
---
drivers/gpu/drm/panel/panel-simple.c | 109 +++++++++++++++++++++++++--
1 file changed, 104 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index af6bf5611b4e..1bee197821ef 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -30,6 +30,7 @@
#include <linux/regulator/consumer.h>
#include <video/display_timing.h>
+#include <video/of_display_timing.h>
#include <video/videomode.h>
#include <drm/drm_crtc.h>
@@ -92,6 +93,8 @@ struct panel_simple {
struct i2c_adapter *ddc;
struct gpio_desc *enable_gpio;
+
+ struct drm_display_mode override_mode;
};
static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
@@ -99,16 +102,13 @@ static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
return container_of(panel, struct panel_simple, base);
}
-static int panel_simple_get_fixed_modes(struct panel_simple *panel)
+static unsigned int panel_simple_get_timings_modes(struct panel_simple *panel)
{
struct drm_connector *connector = panel->base.connector;
struct drm_device *drm = panel->base.drm;
struct drm_display_mode *mode;
unsigned int i, num = 0;
- if (!panel->desc)
- return 0;
-
for (i = 0; i < panel->desc->num_timings; i++) {
const struct display_timing *dt = &panel->desc->timings[i];
struct videomode vm;
@@ -132,6 +132,16 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel)
num++;
}
+ return num;
+}
+
+static unsigned int panel_simple_get_fixed_modes(struct panel_simple *panel)
+{
+ struct drm_connector *connector = panel->base.connector;
+ struct drm_device *drm = panel->base.drm;
+ struct drm_display_mode *mode;
+ unsigned int i, num = 0;
+
for (i = 0; i < panel->desc->num_modes; i++) {
const struct drm_display_mode *m = &panel->desc->modes[i];
@@ -153,6 +163,44 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel)
num++;
}
+ return num;
+}
+
+static int panel_simple_get_non_edid_modes(struct panel_simple *panel)
+{
+ struct drm_connector *connector = panel->base.connector;
+ struct drm_device *drm = panel->base.drm;
+ struct drm_display_mode *mode;
+ bool has_override = panel->override_mode.type;
+ unsigned int num = 0;
+
+ if (!panel->desc)
+ return 0;
+
+ if (has_override) {
+ mode = drm_mode_duplicate(drm, &panel->override_mode);
+ if (mode) {
+ drm_mode_probed_add(connector, mode);
+ num = 1;
+ } else {
+ dev_err(drm->dev, "failed to add override mode\n");
+ }
+ }
+
+ /* Only add timings if override was not there or failed to validate */
+ if (num == 0 && panel->desc->num_timings)
+ num = panel_simple_get_timings_modes(panel);
+
+ /*
+ * Only add fixed modes if timings/override added no mode.
+ *
+ * We should only ever have either the display timings specified
+ * or a fixed mode. Anything else is rather bogus.
+ */
+ WARN_ON(panel->desc->num_timings && panel->desc->num_modes);
+ if (num == 0)
+ num = panel_simple_get_fixed_modes(panel);
+
connector->display_info.bpc = panel->desc->bpc;
connector->display_info.width_mm = panel->desc->size.width;
connector->display_info.height_mm = panel->desc->size.height;
@@ -269,7 +317,7 @@ static int panel_simple_get_modes(struct drm_panel *panel)
}
/* add hard-coded panel modes */
- num += panel_simple_get_fixed_modes(p);
+ num += panel_simple_get_non_edid_modes(p);
return num;
}
@@ -300,10 +348,58 @@ static const struct drm_panel_funcs panel_simple_funcs = {
.get_timings = panel_simple_get_timings,
};
+#define PANEL_SIMPLE_BOUNDS_CHECK(to_check, bounds, field) \
+ (to_check->field.typ >= bounds->field.min && \
+ to_check->field.typ <= bounds->field.max)
+static void panel_simple_parse_override_mode(struct device *dev,
+ struct panel_simple *panel,
+ const struct display_timing *ot)
+{
+ const struct panel_desc *desc = panel->desc;
+ struct videomode vm;
+ unsigned int i;
+
+ if (WARN_ON(desc->num_modes)) {
+ dev_err(dev, "Reject override mode: panel has a fixed mode\n");
+ return;
+ }
+ if (WARN_ON(!desc->num_timings)) {
+ dev_err(dev, "Reject override mode: no timings specified\n");
+ return;
+ }
+
+ for (i = 0; i < panel->desc->num_timings; i++) {
+ const struct display_timing *dt = &panel->desc->timings[i];
+
+ if (!PANEL_SIMPLE_BOUNDS_CHECK(ot, dt, hactive) ||
+ !PANEL_SIMPLE_BOUNDS_CHECK(ot, dt, hfront_porch) ||
+ !PANEL_SIMPLE_BOUNDS_CHECK(ot, dt, hback_porch) ||
+ !PANEL_SIMPLE_BOUNDS_CHECK(ot, dt, hsync_len) ||
+ !PANEL_SIMPLE_BOUNDS_CHECK(ot, dt, vactive) ||
+ !PANEL_SIMPLE_BOUNDS_CHECK(ot, dt, vfront_porch) ||
+ !PANEL_SIMPLE_BOUNDS_CHECK(ot, dt, vback_porch) ||
+ !PANEL_SIMPLE_BOUNDS_CHECK(ot, dt, vsync_len))
+ continue;
+
+ if (ot->flags != dt->flags)
+ continue;
+
+ videomode_from_timing(ot, &vm);
+ drm_display_mode_from_videomode(&vm, &panel->override_mode);
+ panel->override_mode.type |= DRM_MODE_TYPE_DRIVER |
+ DRM_MODE_TYPE_PREFERRED;
+ break;
+ }
+
+ if (WARN_ON(!panel->override_mode.type))
+ dev_err(dev, "Reject override mode: No display_timing found\n");
+}
+
static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
{
struct device_node *backlight, *ddc;
struct panel_simple *panel;
+ struct display_timing dt;
int err;
panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
@@ -349,6 +445,9 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
}
}
+ if (!of_get_display_timing(dev->of_node, "panel-timing", &dt))
+ panel_simple_parse_override_mode(dev, panel, &dt);
+
drm_panel_init(&panel->base);
panel->base.dev = dev;
panel->base.funcs = &panel_simple_funcs;
--
2.22.0.410.gd8fdbe21b5-goog
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related
* Re: [PATCH 5/6] irqchip/irq-pruss-intc: Add API to trigger a PRU sysevent
From: David Lechner @ 2019-07-11 20:40 UTC (permalink / raw)
To: Suman Anna, Marc Zyngier, Rob Herring, Thomas Gleixner,
Jason Cooper
Cc: Tony Lindgren, Andrew F. Davis, Roger Quadros, Lokesh Vutla,
Grygorii Strashko, Sekhar Nori, Murali Karicheri, devicetree,
linux-omap, linux-arm-kernel, linux-kernel
In-Reply-To: <20190708035243.12170-6-s-anna@ti.com>
On 7/7/19 10:52 PM, Suman Anna wrote:
> From: "Andrew F. Davis" <afd@ti.com>
>
> The PRUSS INTC can generate an interrupt to various processor
> subsystems on the SoC through a set of 64 possible PRU system
> events. These system events can be used by PRU client drivers
> or applications for event notifications/signalling between PRUs
> and MPU or other processors. A new API, pruss_intc_trigger() is
> provided to MPU-side PRU client drivers/applications to be able
> to trigger an event/interrupt using IRQ numbers provided by the
> PRUSS-INTC irqdomain chip.
>
> Signed-off-by: Andrew F. Davis <afd@ti.com>
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
> drivers/irqchip/irq-pruss-intc.c | 31 +++++++++++++++++++++++++++++++
> include/linux/pruss_intc.h | 26 ++++++++++++++++++++++++++
> 2 files changed, 57 insertions(+)
> create mode 100644 include/linux/pruss_intc.h
>
> diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
> index 8118c2a2ac43..a0ad50b95cd5 100644
> --- a/drivers/irqchip/irq-pruss-intc.c
> +++ b/drivers/irqchip/irq-pruss-intc.c
> @@ -421,6 +421,37 @@ static void pruss_intc_irq_relres(struct irq_data *data)
> module_put(THIS_MODULE);
> }
>
> +/**
> + * pruss_intc_trigger() - trigger a PRU system event
> + * @irq: linux IRQ number associated with a PRU system event
> + *
> + * Trigger an interrupt by signaling a specific PRU system event.
> + * This can be used by PRUSS client users to raise/send an event to
> + * a PRU or any other core that is listening on the host interrupt
> + * mapped to that specific PRU system event. The @irq variable is the
> + * Linux IRQ number associated with a specific PRU system event that
> + * a client user/application uses. The interrupt mappings for this is
> + * provided by the PRUSS INTC irqchip instance.
> + *
> + * Returns 0 on success, or an error value upon failure.
> + */
> +int pruss_intc_trigger(unsigned int irq)
> +{
> + struct irq_desc *desc;
> +
> + if (irq <= 0)
> + return -EINVAL;
> +
> + desc = irq_to_desc(irq);
> + if (!desc)
> + return -EINVAL;
> +
> + pruss_intc_irq_retrigger(&desc->irq_data);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_intc_trigger);
Although it is not quite as obvious, we can do the same thing with:
irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, true);
So I don't think a new API is needed. We just need to implement the
irq_set_irqchip_state callback as in the following patch.
---
From c5991a11a19858d74e2a184b76c3ef5823f09ef6 Mon Sep 17 00:00:00 2001
From: David Lechner <david@lechnology.com>
Date: Thu, 11 Jul 2019 15:33:29 -0500
Subject: [PATCH] irqchip/irq-pruss-intc: implement irq_{get,set}_irqchip_state
This implements the irq_get_irqchip_state and irq_set_irqchip_state
callbacks for the TI PRUSS INTC driver. The set callback can be used
by drivers to "kick" a PRU by enabling a PRU system event.
Example:
irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, true);
Signed-off-by: David Lechner <david@lechnology.com>
---
drivers/irqchip/irq-pruss-intc.c | 41 ++++++++++++++++++++++++++++++--
1 file changed, 39 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index dd14addfd0b4..129dfd52248b 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -7,6 +7,7 @@
* Suman Anna <s-anna@ti.com>
*/
+#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
@@ -46,8 +47,7 @@
#define PRU_INTC_HIEISR 0x0034
#define PRU_INTC_HIDISR 0x0038
#define PRU_INTC_GPIR 0x0080
-#define PRU_INTC_SRSR0 0x0200
-#define PRU_INTC_SRSR1 0x0204
+#define PRU_INTC_SRSR(x) (0x0200 + (x) * 4)
#define PRU_INTC_SECR0 0x0280
#define PRU_INTC_SECR1 0x0284
#define PRU_INTC_ESR0 0x0300
@@ -386,6 +386,41 @@ static void pruss_intc_irq_relres(struct irq_data *data)
module_put(THIS_MODULE);
}
+static int pruss_intc_irq_get_irqchip_state(struct irq_data *data,
+ enum irqchip_irq_state which,
+ bool *state)
+{
+ struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+ u32 reg, mask, srsr;
+
+ if (which != IRQCHIP_STATE_PENDING)
+ return -EINVAL;
+
+ reg = PRU_INTC_SRSR(data->hwirq / 32);
+ mask = BIT(data->hwirq % 32);
+
+ srsr = pruss_intc_read_reg(intc, reg);
+
+ *state = !!(srsr & mask);
+
+ return 0;
+}
+
+static int pruss_intc_irq_set_irqchip_state(struct irq_data *data,
+ enum irqchip_irq_state which,
+ bool state)
+{
+ struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+
+ if (which != IRQCHIP_STATE_PENDING)
+ return -EINVAL;
+
+ if (state)
+ return pruss_intc_check_write(intc, PRU_INTC_SISR, data->hwirq);
+
+ return pruss_intc_check_write(intc, PRU_INTC_SICR, data->hwirq);
+}
+
static int
pruss_intc_irq_domain_xlate(struct irq_domain *d, struct device_node *node,
const u32 *intspec, unsigned int intsize,
@@ -583,6 +618,8 @@ static int pruss_intc_probe(struct platform_device *pdev)
irqchip->irq_retrigger = pruss_intc_irq_retrigger;
irqchip->irq_request_resources = pruss_intc_irq_reqres;
irqchip->irq_release_resources = pruss_intc_irq_relres;
+ irqchip->irq_get_irqchip_state = pruss_intc_irq_get_irqchip_state;
+ irqchip->irq_set_irqchip_state = pruss_intc_irq_set_irqchip_state;
irqchip->parent_device = dev;
irqchip->name = dev_name(dev);
intc->irqchip = irqchip;
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v5 6/7] ARM: dts: rockchip: Specify rk3288-veyron-chromebook's display timings
From: Heiko Stübner @ 2019-07-11 21:27 UTC (permalink / raw)
To: Douglas Anderson
Cc: Mark Rutland, devicetree, Rob Herring, linux-kernel, dri-devel,
linux-rockchip, Thierry Reding, Sean Paul, Laurent Pinchart,
Boris Brezillon, Enric Balletbò, Ezequiel Garcia, mka,
linux-arm-kernel
In-Reply-To: <20190401171724.215780-7-dianders@chromium.org>
Am Montag, 1. April 2019, 19:17:23 CEST schrieb Douglas Anderson:
> Let's document the display timings that most veyron chromebooks (like
> jaq, jerry, mighty, speedy) have been using out in the field. This
> uses the standard blankings but a slightly slower clock rate, thus
> getting a refresh rate 58.3 Hz.
>
> NOTE: this won't really do anything except cause DRM to properly
> report the refresh rate since vop_crtc_mode_fixup() was rounding the
> pixel clock to 74.25 MHz anyway. Apparently the adjusted rate isn't
> exposed to userspace so it's important that the rate we're trying to
> achieve is mostly right.
>
> For the downstream kernel change related to this see See
> https://crrev.com/c/324558.
>
> NOTE: minnie uses a different panel will be fixed up in a future
> patch, so for now we'll just delete the panel timings there.
>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
applied for 5.3
Thanks
Heiko
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v5 7/7] ARM: dts: rockchip: Specify rk3288-veyron-minnie's display timings
From: Heiko Stübner @ 2019-07-11 21:28 UTC (permalink / raw)
To: Douglas Anderson
Cc: Mark Rutland, devicetree, Rob Herring, linux-kernel, dri-devel,
linux-rockchip, Thierry Reding, Sean Paul, Laurent Pinchart,
Boris Brezillon, Enric Balletbò, Ezequiel Garcia, mka,
linux-arm-kernel
In-Reply-To: <20190401171724.215780-8-dianders@chromium.org>
Am Montag, 1. April 2019, 19:17:24 CEST schrieb Douglas Anderson:
> Just like we did for rk3288-veyron-chromebook, we want to be able to
> use one of the fixed PLLs in the system to make the pixel clock for
> minnie.
>
> Specifying these timings matches us with how the display is used on
> the downstream Chrome OS kernel. See https://crrev.com/c/323211.
>
> Unlike what we did for rk3288-veyron-chromebook, this CL actually
> changes the timings (though not the pixel clock) that is used when
> using the upstream kernel. Booting up a minnie shows that it ended up
> with a 66.67 MHz pixel clock but it was still using the
> porches/blankings it would have wanted for a 72.5 MHz pixel clock.
>
> NOTE: compared to the downstream kernel, this seems to cause a
> slightly different result reported in the 'modetest' command on a
> Chromebook. The downstream kernel shows:
> 1280x800 60 1280 1298 1330 1351 800 804 822 830 66667
>
> With this patch we have:
> 1280x800 59 1280 1298 1330 1351 800 804 822 830 66666
>
> Specifically modetest was reporting 60 Hz on the downstream kernel but
> the upstream kernel does the math and comesup with 59 (because we
> actually achieve 59.45 Hz). Also upstream doesn't round the Hz up
> when converting to kHz--it seems to truncate.
>
> ALSO NOTE: when I look at the EDID from the datasheet, I see:
> -hsync -vsync
> ...but it seems like we've never actually run with that so I've
> continued leaving that out.
>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
applied for 5.4
Thanks
Heiko
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v5 3/7] arm64: dts: rockchip: Specify override mode for kevin panel
From: Heiko Stübner @ 2019-07-11 21:30 UTC (permalink / raw)
To: Douglas Anderson
Cc: Mark Rutland, devicetree, Brian Norris, Rob Herring, Viresh Kumar,
Jeffy Chen, linux-kernel, dri-devel, linux-rockchip, Klaus Goger,
Thierry Reding, Sean Paul, Laurent Pinchart, Boris Brezillon,
Enric Balletbò, Stéphane Marchesin, Dmitry Torokhov,
Ezequiel Garcia, mka, linux-arm-kernel
In-Reply-To: <20190401171724.215780-4-dianders@chromium.org>
Am Montag, 1. April 2019, 19:17:20 CEST schrieb Douglas Anderson:
> From: Sean Paul <seanpaul@chromium.org>
>
> This patch adds an override mode for kevin devices. The mode increases
> both back porches to allow a pixel clock of 26666kHz as opposed to the
> 'typical' value of 252750kHz. This is needed to avoid interference with
> the touch digitizer on these laptops.
>
> Cc: Doug Anderson <dianders@chromium.org>
> Cc: Eric Anholt <eric@anholt.net>
> Cc: Heiko Stuebner <heiko@sntech.de>
> Cc: Jeffy Chen <jeffy.chen@rock-chips.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Stéphane Marchesin <marcheu@chromium.org>
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: devicetree@vger.kernel.org
> Cc: dri-devel@lists.freedesktop.org
> Cc: linux-rockchip@lists.infradead.org
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
applied for 5.4
Thanks
Heiko
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v5 6/7] ARM: dts: rockchip: Specify rk3288-veyron-chromebook's display timings
From: Heiko Stübner @ 2019-07-11 21:52 UTC (permalink / raw)
To: Douglas Anderson
Cc: Mark Rutland, devicetree, Rob Herring, linux-kernel, dri-devel,
linux-rockchip, Thierry Reding, Sean Paul, Laurent Pinchart,
Boris Brezillon, Enric Balletbò, Ezequiel Garcia, mka,
linux-arm-kernel
In-Reply-To: <4744731.Gbjux09qzx@diego>
Am Donnerstag, 11. Juli 2019, 23:27:44 CEST schrieb Heiko Stübner:
> Am Montag, 1. April 2019, 19:17:23 CEST schrieb Douglas Anderson:
> > Let's document the display timings that most veyron chromebooks (like
> > jaq, jerry, mighty, speedy) have been using out in the field. This
> > uses the standard blankings but a slightly slower clock rate, thus
> > getting a refresh rate 58.3 Hz.
> >
> > NOTE: this won't really do anything except cause DRM to properly
> > report the refresh rate since vop_crtc_mode_fixup() was rounding the
> > pixel clock to 74.25 MHz anyway. Apparently the adjusted rate isn't
> > exposed to userspace so it's important that the rate we're trying to
> > achieve is mostly right.
> >
> > For the downstream kernel change related to this see See
> > https://crrev.com/c/324558.
> >
> > NOTE: minnie uses a different panel will be fixed up in a future
> > patch, so for now we'll just delete the panel timings there.
> >
> > Signed-off-by: Douglas Anderson <dianders@chromium.org>
>
> applied for 5.3
5.4 obviously
[just to not confuse people reading that later]
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH 4/6] irqchip/irq-pruss-intc: Add helper functions to configure internal mapping
From: David Lechner @ 2019-07-11 22:09 UTC (permalink / raw)
To: Suman Anna, Marc Zyngier, Rob Herring, Thomas Gleixner,
Jason Cooper
Cc: Tony Lindgren, Andrew F. Davis, Roger Quadros, Lokesh Vutla,
Grygorii Strashko, Sekhar Nori, Murali Karicheri, devicetree,
linux-omap, linux-arm-kernel, linux-kernel
In-Reply-To: <9aa5acd8-81bf-10dc-5a86-cea2acd1132b@lechnology.com>
On 7/10/19 10:10 PM, David Lechner wrote:
> On 7/7/19 10:52 PM, Suman Anna wrote:
>> The PRUSS INTC receives a number of system input interrupt source events
>> and supports individual control configuration and hardware prioritization.
>> These input events can be mapped to some output host interrupts through 2
>> levels of many-to-one mapping i.e. events to channel mapping and channels
>> to host interrupts.
>>
>> This mapping information is provided through the PRU firmware that is
>> loaded onto a PRU core/s or through the device tree node of the PRU
>
> What will the device tree bindings for this look like?
>
> Looking back at Rob's comment on the initial series [1], I still think
> that increasing the #interrupt-cells sounds like a reasonable solution.
>
> [1]: https://patchwork.kernel.org/patch/10697705/#22375155
>
I have come up with an alternative to this patch that addresses my
previous comments.
I propose that we change the device tree bindings to have:
#interrupt-cells = <3>;
Where the parameters are the system event, the channel and the host
event.
In the case of AM18xx, we will need 4 cells, with the 4th one being
the EVTSEL value (the first 32 events are multiplexed so just giving
the system event is not enough info).
With the patch below, we don't need to introduce any new public APIs.
Instead, we implement the irqchip xlate callback. This parses the
device tree parameters and saves them for later.
For the case where the mapping comes from the PRU firmware instead
of the device tree, the remoteproc driver can just call
irq_create_fwspec_mapping() to register the mapping and the same
xlate function handle it just the same as if it came from a device
tree.
The channel mapping is now done in the irqchip map callback. Reference
counting is used to allow shared channels and host events and still
give an error when there are conflicting requests. This also simplifies
the code a bit since we aren't dealing with multiple mappings at one time.
There is a bit more work to do to get EVTSEL working on AM18xx, but
I've tested that both device tree and irq_create_fwspec_mapping()
work.
Complete set of my hacks can be found at [1].
[1]: https://github.com/dlech/linux/tree/pruss-2019-07-11
---
From 199a13a2f224489bd95e03424c0ae98744dea364 Mon Sep 17 00:00:00 2001
From: Suman Anna <s-anna@ti.com>
Date: Sun, 7 Jul 2019 22:52:41 -0500
Subject: [PATCH] irqchip/irq-pruss-intc: Add event mapping support
The PRUSS INTC receives a number of system input interrupt source events
and supports individual control configuration and hardware prioritization.
These input events can be mapped to some output host interrupts through 2
levels of many-to-one mapping i.e. events to channel mapping and channels
to host interrupts.
This mapping information is provided through the PRU firmware that is
loaded onto a PRU core/s or through the device tree node of the PRU
application. The mapping is configured when an IRQ is requested, and
cleaned up when the IRQ is freed. Reference counting is used to allow
multiple system events to share a single channel and to allow multiple
channels to share a single host event.
The remoteproc driver can register mappings read from a firmware blob
as shown below. The fwnode parameters must match the device tree
bindings.
struct irq_fwspec fwspec;
int irq;
fwspec.fwnode = of_node_to_fwnode(dev->of_node);
fwspec.param_count = 3;
fwspec.param[0] = 63; // system event
fwspec.param[1] = 5; // channel
fwspec.param[2] = 6; // host event
irq = irq_create_fwspec_mapping(&fwspec);
if (irq < 0) {
dev_err(dev, "failed to get irq\n");
return irq;
}
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Andrew F. Davis <afd@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: David Lechner <david@lechnology.com>
---
drivers/irqchip/irq-pruss-intc.c | 302 ++++++++++++++++++++++++++++++-
1 file changed, 293 insertions(+), 9 deletions(-)
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index 142d01b434e0..dd14addfd0b4 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
/*
* Number of host interrupts reaching the main MPU sub-system. Note that this
@@ -24,6 +25,12 @@
/* minimum starting host interrupt number for MPU */
#define MIN_PRU_HOST_INT 2
+/* maximum number of host interrupts */
+#define MAX_PRU_HOST_INT 10
+
+/* maximum number of interrupt channels */
+#define MAX_PRU_CHANNELS 10
+
/* maximum number of system events */
#define MAX_PRU_SYS_EVENTS 64
@@ -57,29 +64,71 @@
#define PRU_INTC_HINLR(x) (0x1100 + (x) * 4)
#define PRU_INTC_HIER 0x1500
+/* CMR register bit-field macros */
+#define CMR_EVT_MAP_MASK 0xf
+#define CMR_EVT_MAP_BITS 8
+#define CMR_EVT_PER_REG 4
+
+/* HMR register bit-field macros */
+#define HMR_CH_MAP_MASK 0xf
+#define HMR_CH_MAP_BITS 8
+#define HMR_CH_PER_REG 4
+
/* HIPIR register bit-fields */
#define INTC_HIPIR_NONE_HINT 0x80000000
+/**
+ * struct pruss_intc_hwirq_data - additional metadata associated with a PRU
+ * system event
+ * @evtsel: The event select index (AM18xx only)
+ * @channel: The PRU INTC channel that the system event should be mapped to
+ * @host: The PRU INTC host that the channel should be mapped to
+ */
+struct pruss_intc_hwirq_data {
+ u8 evtsel;
+ u8 channel;
+ u8 host;
+};
+
+/**
+ * struct pruss_intc_map_record - keeps track of actual mapping state
+ * @value: The currently mapped value (evtsel, channel or host)
+ * @ref_count: Keeps track of number of current users of this resource
+ */
+struct pruss_intc_map_record {
+ u8 value;
+ u8 ref_count;
+};
+
/**
* struct pruss_intc - PRUSS interrupt controller structure
+ * @hwirq_data: Table of additional mapping data received from device tree
+ * or PRU firmware
+ * @evtsel: Tracks the current state of CFGCHIP3[3].PRUSSEVTSEL (AM18xx only)
+ * @event_channel: Tracks the current state of system event to channel mappings
+ * @channel_host: Tracks the current state of channel to host mappings
* @irqs: kernel irq numbers corresponding to PRUSS host interrupts
* @base: base virtual address of INTC register space
* @irqchip: irq chip for this interrupt controller
* @domain: irq domain for this interrupt controller
* @lock: mutex to serialize access to INTC
- * @host_mask: indicate which HOST IRQs are enabled
* @shared_intr: bit-map denoting if the MPU host interrupt is shared
* @invalid_intr: bit-map denoting if host interrupt is connected to MPU
+ * @has_evtsel: indicates that the chip has an event select mux
*/
struct pruss_intc {
+ struct pruss_intc_hwirq_data hwirq_data[MAX_PRU_SYS_EVENTS];
+ struct pruss_intc_map_record evtsel;
+ struct pruss_intc_map_record event_channel[MAX_PRU_SYS_EVENTS];
+ struct pruss_intc_map_record channel_host[MAX_PRU_CHANNELS];
unsigned int irqs[MAX_NUM_HOST_IRQS];
void __iomem *base;
struct irq_chip *irqchip;
struct irq_domain *domain;
struct mutex lock; /* PRUSS INTC lock */
- u32 host_mask;
u16 shared_intr;
u16 invalid_intr;
+ bool has_evtsel;
};
static inline u32 pruss_intc_read_reg(struct pruss_intc *intc, unsigned int reg)
@@ -107,6 +156,170 @@ static int pruss_intc_check_write(struct pruss_intc *intc, unsigned int reg,
return 0;
}
+/**
+ * pruss_intc_map() - configure the PRUSS INTC
+ * @intc: pru intc pointer
+ * @hwirq: the system event number
+ *
+ * Configures the PRUSS INTC with the provided configuration from the one
+ * parsed in the xlate function. Any existing event to channel mappings or
+ * channel to host interrupt mappings are checked to make sure there are no
+ * conflicting configuration between both the PRU cores.
+ *
+ * Returns 0 on success, or a suitable error code otherwise
+ */
+static int pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq)
+{
+ struct device* dev = intc->irqchip->parent_device;
+ u32 val;
+ int idx, ret;
+ u8 evtsel, ch, host;
+
+ if (hwirq >= MAX_PRU_SYS_EVENTS)
+ return -EINVAL;
+
+ mutex_lock(&intc->lock);
+
+ evtsel = intc->hwirq_data[hwirq].evtsel;
+ ch = intc->hwirq_data[hwirq].channel;
+ host = intc->hwirq_data[hwirq].host;
+
+ if (intc->has_evtsel && intc->evtsel.ref_count > 0 &&
+ intc->evtsel.value != evtsel) {
+ dev_err(dev, "event %lu (req. evtsel %d) already assigned to evtsel %d\n",
+ hwirq, evtsel, intc->evtsel.value);
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ /* check if sysevent already assigned */
+ if (intc->event_channel[hwirq].ref_count > 0 &&
+ intc->event_channel[hwirq].value != ch) {
+ dev_err(dev, "event %lu (req. channel %d) already assigned to channel %d\n",
+ hwirq, ch, intc->event_channel[hwirq].value);
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ /* check if channel already assigned */
+ if (intc->channel_host[ch].ref_count > 0 &&
+ intc->channel_host[ch].value != host) {
+ dev_err(dev, "channel %d (req. intr_no %d) already assigned to intr_no %d\n",
+ ch, host, intc->channel_host[ch].value);
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ if (++intc->evtsel.ref_count == 1) {
+ intc->evtsel.value = evtsel;
+
+ /* TODO: need to implement CFGCHIP3[3].PRUSSEVTSEL */
+ }
+
+ if (++intc->event_channel[hwirq].ref_count == 1) {
+ intc->event_channel[hwirq].value = ch;
+
+ /*
+ * configure channel map registers - each register holds map
+ * info for 4 events, with each event occupying the lower nibble
+ * in a register byte address in little-endian fashion
+ */
+ idx = hwirq / CMR_EVT_PER_REG;
+
+ val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx));
+ val &= ~(CMR_EVT_MAP_MASK <<
+ ((hwirq % CMR_EVT_PER_REG) * CMR_EVT_MAP_BITS));
+ val |= ch << ((hwirq % CMR_EVT_PER_REG) * CMR_EVT_MAP_BITS);
+ pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val);
+
+ dev_dbg(dev, "SYSEV%lu -> CH%d (CMR%d 0x%08x)\n", hwirq, ch,
+ idx, pruss_intc_read_reg(intc, PRU_INTC_CMR(idx)));
+
+ /* clear and enable system event */
+ pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq);
+ pruss_intc_write_reg(intc, PRU_INTC_EISR, hwirq);
+ }
+
+ if (++intc->channel_host[ch].ref_count == 1) {
+ intc->channel_host[ch].value = host;
+
+ /*
+ * set host map registers - each register holds map info for
+ * 4 channels, with each channel occupying the lower nibble in
+ * a register byte address in little-endian fashion
+ */
+ idx = ch / HMR_CH_PER_REG;
+
+ val = pruss_intc_read_reg(intc, PRU_INTC_HMR(idx));
+ val &= ~(HMR_CH_MAP_MASK <<
+ ((ch % HMR_CH_PER_REG) * HMR_CH_MAP_BITS));
+ val |= host << ((ch % HMR_CH_PER_REG) * HMR_CH_MAP_BITS);
+ pruss_intc_write_reg(intc, PRU_INTC_HMR(idx), val);
+
+ dev_dbg(dev, "CH%d -> HOST%d (HMR%d 0x%08x)\n", ch, host, idx,
+ pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)));
+
+ /* enable host interrupts */
+ pruss_intc_write_reg(intc, PRU_INTC_HIEISR, host);
+ }
+
+ dev_info(dev, "mapped system_event = %lu channel = %d host = %d\n",
+ hwirq, ch, host);
+
+ /* global interrupt enable */
+ pruss_intc_write_reg(intc, PRU_INTC_GER, 1);
+
+ mutex_unlock(&intc->lock);
+ return 0;
+
+unlock:
+ mutex_unlock(&intc->lock);
+ return ret;
+}
+
+/**
+ * pruss_intc_unmap() - unconfigure the PRUSS INTC
+ * @intc: pru intc pointer
+ * @hwirq: the system event number
+ *
+ * Undo whatever was done in pruss_intc_map() for a PRU core.
+ * Mappings are reference counted, so resources are only disabled when there
+ * are no longer any users.
+ */
+static void pruss_intc_unmap(struct pruss_intc *intc, unsigned long hwirq)
+{
+ struct device* dev = intc->irqchip->parent_device;
+ u8 ch, host;
+
+ if (hwirq >= MAX_PRU_SYS_EVENTS)
+ return;
+
+ mutex_lock(&intc->lock);
+
+ ch = intc->event_channel[hwirq].value;
+ host = intc->channel_host[ch].value;
+
+ if (--intc->channel_host[ch].ref_count == 0) {
+ /* disable host interrupts */
+ pruss_intc_write_reg(intc, PRU_INTC_HIDISR, host);
+ }
+
+ if (--intc->event_channel[hwirq].ref_count == 0) {
+ /* disable system events */
+ pruss_intc_write_reg(intc, PRU_INTC_EICR, hwirq);
+ /* clear any pending status */
+ pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq);
+ }
+
+ if (intc->has_evtsel)
+ intc->evtsel.ref_count--;
+
+ dev_info(dev, "unmapped system_event = %lu channel = %d host = %d\n",
+ hwirq, ch, host);
+
+ mutex_unlock(&intc->lock);
+}
+
static void pruss_intc_init(struct pruss_intc *intc)
{
int i;
@@ -173,10 +386,53 @@ static void pruss_intc_irq_relres(struct irq_data *data)
module_put(THIS_MODULE);
}
+static int
+pruss_intc_irq_domain_xlate(struct irq_domain *d, struct device_node *node,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
+{
+ struct pruss_intc *intc = d->host_data;
+ int num_cells = intc->has_evtsel ? 4 : 3;
+ u32 sys_event, channel, host;
+ u32 evtsel = 0;
+
+ if (WARN_ON(intsize != num_cells))
+ return -EINVAL;
+
+ sys_event = intspec[0];
+ if (sys_event >= MAX_PRU_SYS_EVENTS)
+ return -EINVAL;
+
+ if (intc->has_evtsel)
+ evtsel = intspec[1];
+
+ channel = intspec[intsize - 2];
+ if (channel >= MAX_PRU_CHANNELS)
+ return -EINVAL;
+
+ host = intspec[intsize - 1];
+ if (host >= MAX_PRU_HOST_INT)
+ return -EINVAL;
+
+ intc->hwirq_data[sys_event].evtsel = evtsel;
+ intc->hwirq_data[sys_event].channel = channel;
+ intc->hwirq_data[sys_event].host = host;
+
+ *out_hwirq = sys_event;
+ *out_type = IRQ_TYPE_NONE;
+
+ return 0;
+}
+
static int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
struct pruss_intc *intc = d->host_data;
+ int err;
+
+ err = pruss_intc_map(intc, hw);
+ if (err < 0)
+ return err;
irq_set_chip_data(virq, intc);
irq_set_chip_and_handler(virq, intc->irqchip, handle_level_irq);
@@ -186,12 +442,20 @@ static int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq,
static void pruss_intc_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
{
+ struct pruss_intc *intc = d->host_data;
+ int i;
+
+ for (i = 0; i < MAX_NUM_HOST_IRQS; i++)
+ if (intc->irqs[i] == virq)
+ break;
+
irq_set_chip_and_handler(virq, NULL, NULL);
irq_set_chip_data(virq, NULL);
+ pruss_intc_unmap(intc, i);
}
static const struct irq_domain_ops pruss_intc_irq_domain_ops = {
- .xlate = irq_domain_xlate_onecell,
+ .xlate = pruss_intc_irq_domain_xlate,
.map = pruss_intc_irq_domain_map,
.unmap = pruss_intc_irq_domain_unmap,
};
@@ -247,7 +511,7 @@ static int pruss_intc_probe(struct platform_device *pdev)
struct pruss_intc *intc;
struct resource *res;
struct irq_chip *irqchip;
- int i, irq, count;
+ int i, err, irq, count;
u8 temp_intr[MAX_NUM_HOST_IRQS] = { 0 };
intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL);
@@ -298,13 +562,20 @@ static int pruss_intc_probe(struct platform_device *pdev)
}
}
+ /* TODO: get intc->has_evtsel from device tree */
+
mutex_init(&intc->lock);
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
pruss_intc_init(intc);
irqchip = devm_kzalloc(dev, sizeof(*irqchip), GFP_KERNEL);
- if (!irqchip)
- return -ENOMEM;
+ if (!irqchip) {
+ err = -ENOMEM;
+ goto fail_alloc;
+ }
irqchip->irq_ack = pruss_intc_irq_ack;
irqchip->irq_mask = pruss_intc_irq_mask;
@@ -312,14 +583,17 @@ static int pruss_intc_probe(struct platform_device *pdev)
irqchip->irq_retrigger = pruss_intc_irq_retrigger;
irqchip->irq_request_resources = pruss_intc_irq_reqres;
irqchip->irq_release_resources = pruss_intc_irq_relres;
+ irqchip->parent_device = dev;
irqchip->name = dev_name(dev);
intc->irqchip = irqchip;
/* always 64 events */
intc->domain = irq_domain_add_linear(dev->of_node, MAX_PRU_SYS_EVENTS,
&pruss_intc_irq_domain_ops, intc);
- if (!intc->domain)
- return -ENOMEM;
+ if (!intc->domain) {
+ err = -ENOMEM;
+ goto fail_alloc;
+ }
for (i = 0; i < MAX_NUM_HOST_IRQS; i++) {
irq = platform_get_irq_byname(pdev, irq_names[i]);
@@ -330,6 +604,7 @@ static int pruss_intc_probe(struct platform_device *pdev)
dev_err(dev->parent, "platform_get_irq_byname failed for %s : %d\n",
irq_names[i], irq);
+ err = irq;
goto fail_irq;
}
@@ -347,12 +622,18 @@ static int pruss_intc_probe(struct platform_device *pdev)
NULL);
}
irq_domain_remove(intc->domain);
- return irq;
+
+fail_alloc:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
+ return err;
}
static int pruss_intc_remove(struct platform_device *pdev)
{
struct pruss_intc *intc = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
unsigned int hwirq;
int i;
@@ -369,6 +650,9 @@ static int pruss_intc_remove(struct platform_device *pdev)
irq_domain_remove(intc->domain);
}
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
return 0;
}
--
2.17.1
^ permalink raw reply related
* [PATCH v2 1/2] ARM: dts: rockchip: move rk3288-veryon display settings into a separate file
From: Matthias Kaehlcke @ 2019-07-11 22:34 UTC (permalink / raw)
To: Heiko Stuebner, Rob Herring, Mark Rutland
Cc: linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Matthias Kaehlcke, Douglas Anderson,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
The chromebook .dtsi file contains common settings for veyron
Chromebooks with eDP displays. Some veyron devices with a display
aren't Chromebooks (e.g. 'tiger' aka 'AOpen Chromebase Mini'), move
display related bits from the chromebook .dtsi into a separate file
to avoid redundant DT settings.
The new file is included from the chromebook .dtsi and can be
included by non-Chromebook devices with a display.
Signed-off-by: Matthias Kaehlcke <mka-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
Changes in v2:
- rebased on v5.4-armsoc/dts32 (0d19541e3b45)
---
.../boot/dts/rk3288-veyron-chromebook.dtsi | 115 +---------------
arch/arm/boot/dts/rk3288-veyron-edp.dtsi | 124 ++++++++++++++++++
2 files changed, 125 insertions(+), 114 deletions(-)
create mode 100644 arch/arm/boot/dts/rk3288-veyron-edp.dtsi
diff --git a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
index 6a28ce345ba0..ffb60f880b39 100644
--- a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
@@ -10,6 +10,7 @@
#include <dt-bindings/input/input.h>
#include "rk3288-veyron.dtsi"
#include "rk3288-veyron-analog-audio.dtsi"
+#include "rk3288-veyron-edp.dtsi"
#include "rk3288-veyron-sdmmc.dtsi"
/ {
@@ -18,50 +19,6 @@
i2c20 = &i2c_tunnel;
};
- backlight: backlight {
- compatible = "pwm-backlight";
- brightness-levels = <
- 0 1 2 3 4 5 6 7
- 8 9 10 11 12 13 14 15
- 16 17 18 19 20 21 22 23
- 24 25 26 27 28 29 30 31
- 32 33 34 35 36 37 38 39
- 40 41 42 43 44 45 46 47
- 48 49 50 51 52 53 54 55
- 56 57 58 59 60 61 62 63
- 64 65 66 67 68 69 70 71
- 72 73 74 75 76 77 78 79
- 80 81 82 83 84 85 86 87
- 88 89 90 91 92 93 94 95
- 96 97 98 99 100 101 102 103
- 104 105 106 107 108 109 110 111
- 112 113 114 115 116 117 118 119
- 120 121 122 123 124 125 126 127
- 128 129 130 131 132 133 134 135
- 136 137 138 139 140 141 142 143
- 144 145 146 147 148 149 150 151
- 152 153 154 155 156 157 158 159
- 160 161 162 163 164 165 166 167
- 168 169 170 171 172 173 174 175
- 176 177 178 179 180 181 182 183
- 184 185 186 187 188 189 190 191
- 192 193 194 195 196 197 198 199
- 200 201 202 203 204 205 206 207
- 208 209 210 211 212 213 214 215
- 216 217 218 219 220 221 222 223
- 224 225 226 227 228 229 230 231
- 232 233 234 235 236 237 238 239
- 240 241 242 243 244 245 246 247
- 248 249 250 251 252 253 254 255>;
- default-brightness-level = <128>;
- enable-gpios = <&gpio7 RK_PA2 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&bl_en>;
- pwms = <&pwm0 0 1000000 0>;
- post-pwm-on-delay-ms = <10>;
- pwm-off-delay-ms = <10>;
- };
-
gpio-charger {
compatible = "gpio-charger";
charger-type = "mains";
@@ -85,35 +42,6 @@
};
};
- panel: panel {
- compatible ="innolux,n116bge", "simple-panel";
- status = "okay";
- power-supply = <&vcc33_lcd>;
- backlight = <&backlight>;
-
- panel-timing {
- clock-frequency = <74250000>;
- hactive = <1366>;
- hfront-porch = <136>;
- hback-porch = <60>;
- hsync-len = <30>;
- hsync-active = <0>;
- vactive = <768>;
- vfront-porch = <8>;
- vback-porch = <12>;
- vsync-len = <12>;
- vsync-active = <0>;
- };
-
- ports {
- panel_in: port {
- panel_in_edp: endpoint {
- remote-endpoint = <&edp_out_panel>;
- };
- };
- };
- };
-
/* A non-regulated voltage from power supply or battery */
vccsys: vccsys {
compatible = "regulator-fixed";
@@ -155,33 +83,6 @@
};
};
-&edp {
- status = "okay";
-
- pinctrl-names = "default";
- pinctrl-0 = <&edp_hpd>;
-
- ports {
- edp_out: port@1 {
- reg = <1>;
- #address-cells = <1>;
- #size-cells = <0>;
- edp_out_panel: endpoint@0 {
- reg = <0>;
- remote-endpoint = <&panel_in_edp>;
- };
- };
- };
-};
-
-&edp_phy {
- status = "okay";
-};
-
-&pwm0 {
- status = "okay";
-};
-
&rk808 {
vcc11-supply = <&vcc_5v>;
@@ -234,14 +135,6 @@
};
};
-&vopl {
- status = "okay";
-};
-
-&vopl_mmu {
- status = "okay";
-};
-
&pinctrl {
pinctrl-0 = <
/* Common for sleep and wake, but no owners */
@@ -264,12 +157,6 @@
&bt_dev_wake_sleep
>;
- backlight {
- bl_en: bl-en {
- rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
buttons {
ap_lid_int_l: ap-lid-int-l {
rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-edp.dtsi b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
new file mode 100644
index 000000000000..5d812e9e78aa
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Google Veyron (and derivatives) fragment for the edp displays
+ *
+ * Copyright 2019 Google LLC
+ */
+
+/ {
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ brightness-levels = <
+ 0 1 2 3 4 5 6 7
+ 8 9 10 11 12 13 14 15
+ 16 17 18 19 20 21 22 23
+ 24 25 26 27 28 29 30 31
+ 32 33 34 35 36 37 38 39
+ 40 41 42 43 44 45 46 47
+ 48 49 50 51 52 53 54 55
+ 56 57 58 59 60 61 62 63
+ 64 65 66 67 68 69 70 71
+ 72 73 74 75 76 77 78 79
+ 80 81 82 83 84 85 86 87
+ 88 89 90 91 92 93 94 95
+ 96 97 98 99 100 101 102 103
+ 104 105 106 107 108 109 110 111
+ 112 113 114 115 116 117 118 119
+ 120 121 122 123 124 125 126 127
+ 128 129 130 131 132 133 134 135
+ 136 137 138 139 140 141 142 143
+ 144 145 146 147 148 149 150 151
+ 152 153 154 155 156 157 158 159
+ 160 161 162 163 164 165 166 167
+ 168 169 170 171 172 173 174 175
+ 176 177 178 179 180 181 182 183
+ 184 185 186 187 188 189 190 191
+ 192 193 194 195 196 197 198 199
+ 200 201 202 203 204 205 206 207
+ 208 209 210 211 212 213 214 215
+ 216 217 218 219 220 221 222 223
+ 224 225 226 227 228 229 230 231
+ 232 233 234 235 236 237 238 239
+ 240 241 242 243 244 245 246 247
+ 248 249 250 251 252 253 254 255>;
+ default-brightness-level = <128>;
+ enable-gpios = <&gpio7 RK_PA2 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bl_en>;
+ pwms = <&pwm0 0 1000000 0>;
+ post-pwm-on-delay-ms = <10>;
+ pwm-off-delay-ms = <10>;
+ };
+
+ panel: panel {
+ compatible ="innolux,n116bge", "simple-panel";
+ status = "okay";
+ power-supply = <&vcc33_lcd>;
+ backlight = <&backlight>;
+
+ panel-timing {
+ clock-frequency = <74250000>;
+ hactive = <1366>;
+ hfront-porch = <136>;
+ hback-porch = <60>;
+ hsync-len = <30>;
+ hsync-active = <0>;
+ vactive = <768>;
+ vfront-porch = <8>;
+ vback-porch = <12>;
+ vsync-len = <12>;
+ vsync-active = <0>;
+ };
+
+ ports {
+ panel_in: port {
+ panel_in_edp: endpoint {
+ remote-endpoint = <&edp_out_panel>;
+ };
+ };
+ };
+ };
+};
+
+&edp {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&edp_hpd>;
+
+ ports {
+ edp_out: port@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ edp_out_panel: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&panel_in_edp>;
+ };
+ };
+ };
+};
+
+&edp_phy {
+ status = "okay";
+};
+
+&pinctrl {
+ backlight {
+ bl_en: bl-en {
+ rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&pwm0 {
+ status = "okay";
+};
+
+&vopl {
+ status = "okay";
+};
+
+&vopl_mmu {
+ status = "okay";
+};
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* [PATCH v2 2/2] ARM: dts: rockchip: consolidate veyron panel and backlight settings
From: Matthias Kaehlcke @ 2019-07-11 22:34 UTC (permalink / raw)
To: Heiko Stuebner, Rob Herring, Mark Rutland
Cc: linux-rockchip, Matthias Kaehlcke, Douglas Anderson,
linux-arm-kernel, devicetree
In-Reply-To: <20190711223455.12210-1-mka@chromium.org>
veyron jaq, jerry, minnie and speedy have mostly redundant regulator
and pinctrl configurations for the panel/backlight. Consolidate these
pieces in the eDP .dtsi.
Also change the default power supply for the panel to
'panel_regulator', instead of overriding it in all the board files.
pinky is the only device that uses 'vcc33_lcd' (the prior default),
so overwrite it in this case. pinky doesn't have a complete display
configuration, to keep things as they were delete the common nodes
that didn't exist previously in pinky's board file.
Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v2:
- rebased on v5.4-armsoc/dts32 (0d19541e3b45)
---
arch/arm/boot/dts/rk3288-veyron-edp.dtsi | 51 ++++++++++++++++++-
arch/arm/boot/dts/rk3288-veyron-jaq.dts | 55 --------------------
arch/arm/boot/dts/rk3288-veyron-jerry.dts | 58 ----------------------
arch/arm/boot/dts/rk3288-veyron-minnie.dts | 51 -------------------
arch/arm/boot/dts/rk3288-veyron-pinky.dts | 17 +++++++
arch/arm/boot/dts/rk3288-veyron-speedy.dts | 58 ----------------------
6 files changed, 67 insertions(+), 223 deletions(-)
diff --git a/arch/arm/boot/dts/rk3288-veyron-edp.dtsi b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
index 5d812e9e78aa..39f56d36a701 100644
--- a/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
@@ -6,6 +6,40 @@
*/
/ {
+ backlight_regulator: backlight-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bl_pwr_en>;
+ regulator-name = "backlight_regulator";
+ vin-supply = <&vcc33_sys>;
+ startup-delay-us = <15000>;
+ };
+
+ panel_regulator: panel-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcd_enable_h>;
+ regulator-name = "panel_regulator";
+ startup-delay-us = <100000>;
+ vin-supply = <&vcc33_sys>;
+ };
+
+ vcc18_lcd: vcc18-lcd {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&avdd_1v8_disp_en>;
+ regulator-name = "vcc18_lcd";
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc18_wl>;
+ };
+
backlight: backlight {
compatible = "pwm-backlight";
brightness-levels = <
@@ -48,12 +82,13 @@
pwms = <&pwm0 0 1000000 0>;
post-pwm-on-delay-ms = <10>;
pwm-off-delay-ms = <10>;
+ power-supply = <&backlight_regulator>;
};
panel: panel {
compatible ="innolux,n116bge", "simple-panel";
status = "okay";
- power-supply = <&vcc33_lcd>;
+ power-supply = <&panel_regulator>;
backlight = <&backlight>;
panel-timing {
@@ -105,10 +140,24 @@
&pinctrl {
backlight {
+ bl_pwr_en: bl_pwr_en {
+ rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
bl_en: bl-en {
rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
+
+ lcd {
+ lcd_enable_h: lcd-en {
+ rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ avdd_1v8_disp_en: avdd-1v8-disp-en {
+ rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
};
&pwm0 {
diff --git a/arch/arm/boot/dts/rk3288-veyron-jaq.dts b/arch/arm/boot/dts/rk3288-veyron-jaq.dts
index fcd119168cb6..80386203e85b 100644
--- a/arch/arm/boot/dts/rk3288-veyron-jaq.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-jaq.dts
@@ -16,40 +16,6 @@
"google,veyron-jaq-rev3", "google,veyron-jaq-rev2",
"google,veyron-jaq-rev1", "google,veyron-jaq",
"google,veyron", "rockchip,rk3288";
-
- panel_regulator: panel-regulator {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&lcd_enable_h>;
- regulator-name = "panel_regulator";
- startup-delay-us = <100000>;
- vin-supply = <&vcc33_sys>;
- };
-
- vcc18_lcd: vcc18-lcd {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&avdd_1v8_disp_en>;
- regulator-name = "vcc18_lcd";
- regulator-always-on;
- regulator-boot-on;
- vin-supply = <&vcc18_wl>;
- };
-
- backlight_regulator: backlight-regulator {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&bl_pwr_en>;
- regulator-name = "backlight_regulator";
- vin-supply = <&vcc33_sys>;
- startup-delay-us = <15000>;
- };
};
&backlight {
@@ -87,11 +53,6 @@
232 233 234 235 236 237 238 239
240 241 242 243 244 245 246 247
248 249 250 251 252 253 254 255>;
- power-supply = <&backlight_regulator>;
-};
-
-&panel {
- power-supply = <&panel_regulator>;
};
&rk808 {
@@ -343,12 +304,6 @@
};
&pinctrl {
- backlight {
- bl_pwr_en: bl_pwr_en {
- rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
buck-5v {
drv_5v: drv-5v {
rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -361,16 +316,6 @@
};
};
- lcd {
- lcd_enable_h: lcd-en {
- rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
- };
-
- avdd_1v8_disp_en: avdd-1v8-disp-en {
- rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
pmic {
dvs_1: dvs-1 {
rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-jerry.dts b/arch/arm/boot/dts/rk3288-veyron-jerry.dts
index 164561f04c1d..a8f55aec09ee 100644
--- a/arch/arm/boot/dts/rk3288-veyron-jerry.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-jerry.dts
@@ -18,48 +18,6 @@
"google,veyron-jerry-rev5", "google,veyron-jerry-rev4",
"google,veyron-jerry-rev3", "google,veyron-jerry",
"google,veyron", "rockchip,rk3288";
-
- panel_regulator: panel-regulator {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&lcd_enable_h>;
- regulator-name = "panel_regulator";
- startup-delay-us = <100000>;
- vin-supply = <&vcc33_sys>;
- };
-
- vcc18_lcd: vcc18-lcd {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&avdd_1v8_disp_en>;
- regulator-name = "vcc18_lcd";
- regulator-always-on;
- regulator-boot-on;
- vin-supply = <&vcc18_wl>;
- };
-
- backlight_regulator: backlight-regulator {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&bl_pwr_en>;
- regulator-name = "backlight_regulator";
- vin-supply = <&vcc33_sys>;
- startup-delay-us = <15000>;
- };
-};
-
-&backlight {
- power-supply = <&backlight_regulator>;
-};
-
-&panel {
- power-supply= <&panel_regulator>;
};
&rk808 {
@@ -311,12 +269,6 @@
};
&pinctrl {
- backlight {
- bl_pwr_en: bl_pwr_en {
- rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
buck-5v {
drv_5v: drv-5v {
rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -329,16 +281,6 @@
};
};
- lcd {
- lcd_enable_h: lcd-en {
- rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
- };
-
- avdd_1v8_disp_en: avdd-1v8-disp-en {
- rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
pmic {
dvs_1: dvs-1 {
rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
index 4cc7d3659484..2b0801a539c9 100644
--- a/arch/arm/boot/dts/rk3288-veyron-minnie.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
@@ -15,40 +15,6 @@
"google,veyron-minnie-rev0", "google,veyron-minnie",
"google,veyron", "rockchip,rk3288";
- backlight_regulator: backlight-regulator {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&bl_pwr_en>;
- regulator-name = "backlight_regulator";
- vin-supply = <&vcc33_sys>;
- startup-delay-us = <15000>;
- };
-
- panel_regulator: panel-regulator {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&lcd_enable_h>;
- regulator-name = "panel_regulator";
- startup-delay-us = <100000>;
- vin-supply = <&vcc33_sys>;
- };
-
- vcc18_lcd: vcc18-lcd {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&avdd_1v8_disp_en>;
- regulator-name = "vcc18_lcd";
- regulator-always-on;
- regulator-boot-on;
- vin-supply = <&vcc18_wl>;
- };
-
volume_buttons: volume-buttons {
compatible = "gpio-keys";
pinctrl-names = "default";
@@ -137,7 +103,6 @@
&panel {
compatible = "auo,b101ean01", "simple-panel";
- power-supply= <&panel_regulator>;
/delete-node/ panel-timing;
@@ -411,12 +376,6 @@
};
&pinctrl {
- backlight {
- bl_pwr_en: bl_pwr_en {
- rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
buck-5v {
drv_5v: drv-5v {
rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -439,16 +398,6 @@
};
};
- lcd {
- lcd_enable_h: lcd-en {
- rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
- };
-
- avdd_1v8_disp_en: avdd-1v8-disp-en {
- rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
pmic {
dvs_1: dvs-1 {
rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-pinky.dts b/arch/arm/boot/dts/rk3288-veyron-pinky.dts
index 9b6f4d9b03b6..06af58e37a4b 100644
--- a/arch/arm/boot/dts/rk3288-veyron-pinky.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-pinky.dts
@@ -14,7 +14,14 @@
compatible = "google,veyron-pinky-rev2", "google,veyron-pinky",
"google,veyron", "rockchip,rk3288";
+ /delete-node/backlight-regulator;
+ /delete-node/panel-regulator;
/delete-node/emmc-pwrseq;
+ /delete-node/vcc18-lcd;
+};
+
+&backlight {
+ /delete-property/power-supply;
};
&emmc {
@@ -52,7 +59,17 @@
i2c-scl-rising-time-ns = <300>;
};
+&panel {
+ power-supply= <&vcc33_lcd>;
+};
+
&pinctrl {
+ /delete-node/ lcd;
+
+ backlight {
+ /delete-node/ bl_pwr_en;
+ };
+
buttons {
pwr_key_h: pwr-key-h {
rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-speedy.dts b/arch/arm/boot/dts/rk3288-veyron-speedy.dts
index 9b140db04456..2f2989bc3f9c 100644
--- a/arch/arm/boot/dts/rk3288-veyron-speedy.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-speedy.dts
@@ -16,44 +16,6 @@
"google,veyron-speedy-rev5", "google,veyron-speedy-rev4",
"google,veyron-speedy-rev3", "google,veyron-speedy-rev2",
"google,veyron-speedy", "google,veyron", "rockchip,rk3288";
-
- panel_regulator: panel-regulator {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&lcd_enable_h>;
- regulator-name = "panel_regulator";
- startup-delay-us = <100000>;
- vin-supply = <&vcc33_sys>;
- };
-
- vcc18_lcd: vcc18-lcd {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&avdd_1v8_disp_en>;
- regulator-name = "vcc18_lcd";
- regulator-always-on;
- regulator-boot-on;
- vin-supply = <&vcc18_wl>;
- };
-
- backlight_regulator: backlight-regulator {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&bl_pwr_en>;
- regulator-name = "backlight_regulator";
- vin-supply = <&vcc33_sys>;
- startup-delay-us = <15000>;
- };
-};
-
-&backlight {
- power-supply = <&backlight_regulator>;
};
&cpu_alert0 {
@@ -83,10 +45,6 @@
temperature = <90000>;
};
-&panel {
- power-supply= <&panel_regulator>;
-};
-
&rk808 {
pinctrl-names = "default";
pinctrl-0 = <&pmic_int_l>;
@@ -321,12 +279,6 @@
};
&pinctrl {
- backlight {
- bl_pwr_en: bl_pwr_en {
- rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
buck-5v {
drv_5v: drv-5v {
rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -339,16 +291,6 @@
};
};
- lcd {
- lcd_enable_h: lcd-en {
- rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
- };
-
- avdd_1v8_disp_en: avdd-1v8-disp-en {
- rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
pmic {
dvs_1: dvs-1 {
rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* Re: [PATCH 1/6] dt-bindings: pinctrl: aspeed: Document AST2600 pinmux
From: Andrew Jeffery @ 2019-07-12 0:51 UTC (permalink / raw)
To: Rob Herring
Cc: open list:GPIO SUBSYSTEM, Linus Walleij, Mark Rutland,
Joel Stanley, Ryan Chen, Johnny Huang, linux-aspeed, devicetree,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
linux-kernel@vger.kernel.org
In-Reply-To: <CAL_JsqLvY_yxN=-tfUPGn_Bv=UNmntHjXqUhSD1aey79MXznQg@mail.gmail.com>
On Fri, 12 Jul 2019, at 02:48, Rob Herring wrote:
> On Wed, Jul 10, 2019 at 10:19 PM Andrew Jeffery <andrew@aj.id.au> wrote:
> >
> > The AST260 differs from the 2400 and 2500 in that it supports multiple
> > groups for a subset of functions.
> >
> > Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> > ---
> > .../pinctrl/aspeed,ast2600-pinctrl.yaml | 128 ++++++++++++++++++
> > 1 file changed, 128 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml
> > new file mode 100644
> > index 000000000000..dd31f8e62433
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml
> > @@ -0,0 +1,128 @@
> > +# SPDX-License-Identifier: GPL-2.0+
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/pinctrl/aspeed,ast2600-pinctrl.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: ASPEED AST2600 Pin Controller
> > +
> > +maintainers:
> > + - Andrew Jeffery <andrew@aj.id.au>
> > +
> > +description: |+
> > + The pin controller node should be the child of a syscon node with the
> > + required property:
> > +
> > + - compatible: Should be one of the following:
> > + "aspeed,ast2600-scu", "syscon", "simple-mfd"
> > +
> > + Refer to the the bindings described in
> > + Documentation/devicetree/bindings/mfd/syscon.txt
> > +
> > +properties:
> > + compatible:
> > + const: aspeed,ast2600-pinctrl
> > +
> > +patternProperties:
> > + '^.*$':
> > + if:
> > + type: object
> > + then:
> > + patternProperties:
> > + "^function$":
>
> That's a fixed string, not a pattern, so just put under 'properties'.
Haha, good point. Hopefully I'll get the hang of this eventually!
>
> > + allOf:
> > + - $ref: "/schemas/types.yaml#/definitions/string"
> > + - enum: [ "ADC0", "ADC1", "ADC10", "ADC11", "ADC12", "ADC13",
>
> You can drop the quoting here. I wouldn't really care, but yours is
> one of the few right now and everyone will copy.
Yeah, fair point, the quotes add a lot of noise.
>
> > + "ADC14", "ADC15", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC7",
> > + "ADC8", "ADC9", "BMCINT", "ESPI", "ESPIALT", "FSI1", "FSI2",
> > + "FWSPIABR", "FWSPID", "FWSPIWP", "GPIT0", "GPIT1", "GPIT2",
> > + "GPIT3", "GPIT4", "GPIT5", "GPIT6", "GPIT7", "GPIU0", "GPIU1",
> > + "GPIU2", "GPIU3", "GPIU4", "GPIU5", "GPIU6", "GPIU7", "I2C1",
> > + "I2C10", "I2C11", "I2C12", "I2C13", "I2C14", "I2C15", "I2C16",
> > + "I2C2", "I2C3", "I2C4", "I2C5", "I2C6", "I2C7", "I2C8", "I2C9",
> > + "I3C3", "I3C4", "I3C5", "I3C6", "JTAGM", "LHPD", "LHSIRQ", "LPC",
> > + "LPCHC", "LPCPD", "LPCPME", "LPCSMI", "LSIRQ", "MACLINK1",
> > + "MACLINK2", "MACLINK3", "MACLINK4", "MDIO1", "MDIO2", "MDIO3",
> > + "MDIO4", "NCTS1", "NCTS2", "NCTS3", "NCTS4", "NDCD1", "NDCD2",
> > + "NDCD3", "NDCD4", "NDSR1", "NDSR2", "NDSR3", "NDSR4", "NDTR1",
> > + "NDTR2", "NDTR3", "NDTR4", "NRI1", "NRI2", "NRI3", "NRI4",
> > + "NRTS1", "NRTS2", "NRTS3", "NRTS4", "OSCCLK", "PEWAKE", "PWM0",
> > + "PWM1", "PWM10", "PWM11", "PWM12", "PWM13", "PWM14", "PWM15",
> > + "PWM2", "PWM3", "PWM4", "PWM5", "PWM6", "PWM7", "PWM8", "PWM9",
> > + "RGMII1", "RGMII2", "RGMII3", "RGMII4", "RMII1", "RMII2",
> > + "RMII3", "RMII4", "RXD1", "RXD2", "RXD3", "RXD4", "SALT1",
> > + "SALT10", "SALT11", "SALT12", "SALT13", "SALT14", "SALT15",
> > + "SALT16", "SALT2", "SALT3", "SALT4", "SALT5", "SALT6", "SALT7",
> > + "SALT8", "SALT9", "SD1", "SD2", "SD3", "SD3DAT4", "SD3DAT5",
> > + "SD3DAT6", "SD3DAT7", "SGPM1", "SGPS1", "SIOONCTRL", "SIOPBI",
> > + "SIOPBO", "SIOPWREQ", "SIOPWRGD", "SIOS3", "SIOS5", "SIOSCI",
> > + "SPI1", "SPI1ABR", "SPI1CS1", "SPI1WP", "SPI2", "SPI2CS1",
> > + "SPI2CS2", "TACH0", "TACH1", "TACH10", "TACH11", "TACH12",
> > + "TACH13", "TACH14", "TACH15", "TACH2", "TACH3", "TACH4", "TACH5",
> > + "TACH6", "TACH7", "TACH8", "TACH9", "THRU0", "THRU1", "THRU2",
> > + "THRU3", "TXD1", "TXD2", "TXD3", "TXD4", "UART10", "UART11",
> > + "UART12", "UART13", "UART6", "UART7", "UART8", "UART9", "VB",
> > + "VGAHS", "VGAVS", "WDTRST1", "WDTRST2", "WDTRST3", "WDTRST4", ]
> > + "^groups$":
> > + allOf:
> > + - $ref: "/schemas/types.yaml#/definitions/string"
> > + - enum: [ "ADC0", "ADC1", "ADC10", "ADC11", "ADC12", "ADC13",
> > + "ADC14", "ADC15", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC7",
> > + "ADC8", "ADC9", "BMCINT", "ESPI", "ESPIALT", "FSI1", "FSI2",
> > + "FWSPIABR", "FWSPID", "FWQSPID", "FWSPIWP", "GPIT0", "GPIT1",
> > + "GPIT2", "GPIT3", "GPIT4", "GPIT5", "GPIT6", "GPIT7", "GPIU0",
> > + "GPIU1", "GPIU2", "GPIU3", "GPIU4", "GPIU5", "GPIU6", "GPIU7",
> > + "HVI3C3", "HVI3C4", "I2C1", "I2C10", "I2C11", "I2C12", "I2C13",
> > + "I2C14", "I2C15", "I2C16", "I2C2", "I2C3", "I2C4", "I2C5",
> > + "I2C6", "I2C7", "I2C8", "I2C9", "I3C3", "I3C4", "I3C5", "I3C6",
> > + "JTAGM", "LHPD", "LHSIRQ", "LPC", "LPCHC", "LPCPD", "LPCPME",
> > + "LPCSMI", "LSIRQ", "MACLINK1", "MACLINK2", "MACLINK3",
> > + "MACLINK4", "MDIO1", "MDIO2", "MDIO3", "MDIO4", "NCTS1", "NCTS2",
> > + "NCTS3", "NCTS4", "NDCD1", "NDCD2", "NDCD3", "NDCD4", "NDSR1",
> > + "NDSR2", "NDSR3", "NDSR4", "NDTR1", "NDTR2", "NDTR3", "NDTR4",
> > + "NRI1", "NRI2", "NRI3", "NRI4", "NRTS1", "NRTS2", "NRTS3",
> > + "NRTS4", "OSCCLK", "PEWAKE", "PWM0", "PWM1", "PWM10G0",
> > + "PWM10G1", "PWM11G0", "PWM11G1", "PWM12G0", "PWM12G1", "PWM13G0",
> > + "PWM13G1", "PWM14G0", "PWM14G1", "PWM15G0", "PWM15G1", "PWM2",
> > + "PWM3", "PWM4", "PWM5", "PWM6", "PWM7", "PWM8G0", "PWM8G1",
> > + "PWM9G0", "PWM9G1", "QSPI1", "QSPI2", "RGMII1", "RGMII2",
> > + "RGMII3", "RGMII4", "RMII1", "RMII2", "RMII3", "RMII4", "RXD1",
> > + "RXD2", "RXD3", "RXD4", "SALT1", "SALT10G0", "SALT10G1",
> > + "SALT11G0", "SALT11G1", "SALT12G0", "SALT12G1", "SALT13G0",
> > + "SALT13G1", "SALT14G0", "SALT14G1", "SALT15G0", "SALT15G1",
> > + "SALT16G0", "SALT16G1", "SALT2", "SALT3", "SALT4", "SALT5",
> > + "SALT6", "SALT7", "SALT8", "SALT9G0", "SALT9G1", "SD1", "SD2",
> > + "SD3", "SD3DAT4", "SD3DAT5", "SD3DAT6", "SD3DAT7", "SGPM1",
> > + "SGPS1", "SIOONCTRL", "SIOPBI", "SIOPBO", "SIOPWREQ", "SIOPWRGD",
> > + "SIOS3", "SIOS5", "SIOSCI", "SPI1", "SPI1ABR", "SPI1CS1",
> > + "SPI1WP", "SPI2", "SPI2CS1", "SPI2CS2", "TACH0", "TACH1",
> > + "TACH10", "TACH11", "TACH12", "TACH13", "TACH14", "TACH15",
> > + "TACH2", "TACH3", "TACH4", "TACH5", "TACH6", "TACH7", "TACH8",
> > + "TACH9", "THRU0", "THRU1", "THRU2", "THRU3", "TXD1", "TXD2",
> > + "TXD3", "TXD4", "UART10", "UART11", "UART12G0", "UART12G1",
> > + "UART13G0", "UART13G1", "UART6", "UART7", "UART8", "UART9", "VB",
> > + "VGAHS", "VGAVS", "WDTRST1", "WDTRST2", "WDTRST3", "WDTRST4", ]
> > +
> > +required:
> > + - compatible
> > +
> > +examples:
> > + - |
> > + syscon: scu@1e6e2000 {
> > + compatible = "aspeed,ast2600-scu", "syscon", "simple-mfd";
> > + reg = <0x1e6e2000 0xf6c>;
> > +
> > + pinctrl: pinctrl {
> > + compatible = "aspeed,g6-pinctrl";
> > +
> > + pinctrl_pwm10g1_default: pwm10g1_default {
> > + function = "PWM10";
> > + groups = "PWM10G1";
> > + };
> > +
> > + pinctrl_gpioh0_unbiased_default: gpioh0 {
> > + pins = "A18";
> > + bias-disable;
>
> This node and properties aren't getting checked. Need to figure out
> how to do that. That may mean needing some structure to the node
> names. You can worry about that later I suppose.
I surfaced the issue around subnode naming when I updated the 2400
and 2500 pinctrl bindings. As it stands the generic pinctrl bindings do
not impose any constraints on the naming, it's freeform. Converting
the bindings to yaml shouldn't be adding any constraints and
invalidating existing devicetrees. Not really sure how we solve that.
Andrew
^ permalink raw reply
* Re: [PATCH 3/5] dt-bindings: usb: mtk-xhci: add an optional xhci_ck clock
From: Chunfeng Yun @ 2019-07-12 1:53 UTC (permalink / raw)
To: Rob Herring
Cc: Greg Kroah-Hartman, Mark Rutland, Matthias Brugger, Mathias Nyman,
linux-usb, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, Jumin Li
In-Reply-To: <20190709142235.GA11951@bogus>
On Tue, 2019-07-09 at 08:22 -0600, Rob Herring wrote:
> On Wed, Jun 12, 2019 at 01:55:19PM +0800, Chunfeng Yun wrote:
> > Add a new optional clock xhci_ck
> >
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> > ---
> > Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt | 3 ++-
> > 1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt
> > index 266c2d917a28..91c0704b586b 100644
> > --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt
> > +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt
> > @@ -29,6 +29,7 @@ Required properties:
> > "sys_ck": controller clock used by normal mode,
> > the following ones are optional:
> > "ref_ck": reference clock used by low power mode etc,
> > + "xhci_ck": controller clock,
> > "mcu_ck": mcu_bus clock for register access,
> > "dma_ck": dma_bus clock for data transfer by DMA
>
> A new clock should go at the end to stay backwards compatible.
Ok, will fix it, thanks
>
> >
> > @@ -100,7 +101,7 @@ Required properties:
> > - clocks : a list of phandle + clock-specifier pairs, one for each
> > entry in clock-names
> > - clock-names : must contain "sys_ck", and the following ones are optional:
> > - "ref_ck", "mcu_ck" and "dma_ck"
> > + "ref_ck", "xhci_ck", "mcu_ck" and "dma_ck"
> >
> > Optional properties:
> > - vbus-supply : reference to the VBUS regulator;
> > --
> > 2.21.0
> >
^ permalink raw reply
* Re: [GIT PULL] Devicetree updates for 5.3
From: pr-tracker-bot @ 2019-07-12 1:55 UTC (permalink / raw)
To: Rob Herring
Cc: Linus Torvalds, Frank Rowand, linux-kernel@vger.kernel.org,
devicetree, David Miller
In-Reply-To: <CAL_JsqJAydO3Zjx_9S+r8h5YAQbDBJjqHSFV-aKkN9n=MH7erg@mail.gmail.com>
The pull request you sent on Wed, 10 Jul 2019 14:50:01 -0600:
> git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git tags/devicetree-for-5.3
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/d06e4156430e7c5eb4f04dabcaa0d9e2fba335e3
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.wiki.kernel.org/userdoc/prtracker
^ permalink raw reply
* [PATCH v2 0/2] mmc: Add support for the ASPEED SD controller
From: Andrew Jeffery @ 2019-07-12 3:32 UTC (permalink / raw)
To: linux-mmc
Cc: Andrew Jeffery, ulf.hansson, robh+dt, mark.rutland, joel,
adrian.hunter, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, ryanchen.aspeed
Hello,
This is v2 of the ASPEED SD controller driver. v2 primarily addresses Rob's
comments on the bindings in v1. The v1 series can be found here:
https://lists.ozlabs.org/pipermail/linux-aspeed/2019-July/001988.html
Please review!
Andrew
Andrew Jeffery (2):
dt-bindings: mmc: Document Aspeed SD controller
mmc: Add support for the ASPEED SD controller
.../devicetree/bindings/mmc/aspeed,sdhci.yaml | 90 +++++
drivers/mmc/host/Kconfig | 12 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-of-aspeed.c | 326 ++++++++++++++++++
4 files changed, 429 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
create mode 100644 drivers/mmc/host/sdhci-of-aspeed.c
--
2.20.1
^ permalink raw reply
* [PATCH v2 1/2] dt-bindings: mmc: Document Aspeed SD controller
From: Andrew Jeffery @ 2019-07-12 3:32 UTC (permalink / raw)
To: linux-mmc
Cc: Andrew Jeffery, ulf.hansson, robh+dt, mark.rutland, joel,
adrian.hunter, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, ryanchen.aspeed
In-Reply-To: <20190712033214.24713-1-andrew@aj.id.au>
The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the
SDIO Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit
data bus if only a single slot is enabled.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
---
In v2:
* Rename to aspeed,sdhci.yaml
* Rename sd-controller compatible
* Add `maxItems: 1` for reg properties
* Move sdhci subnode description to patternProperties
* Drop sdhci compatible requirement
* #address-cells and #size-cells are required
* Prevent additional properties
* Implement explicit ranges in example
* Remove slot property
.../devicetree/bindings/mmc/aspeed,sdhci.yaml | 90 +++++++++++++++++++
1 file changed, 90 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
diff --git a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
new file mode 100644
index 000000000000..67a691c3348c
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mmc/aspeed,sdhci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED SD/SDIO/eMMC Controller
+
+maintainers:
+ - Andrew Jeffery <andrew@aj.id.au>
+ - Ryan Chen <ryanchen.aspeed@gmail.com>
+
+description: |+
+ The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the SDIO
+ Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit data bus if
+ only a single slot is enabled.
+
+ The two slots are supported by a common configuration area. As the SDHCIs for
+ the slots are dependent on the common configuration area, they are described
+ as child nodes.
+
+properties:
+ compatible:
+ enum: [ aspeed,ast2400-sd-controller, aspeed,ast2500-sd-controller ]
+ reg:
+ maxItems: 1
+ description: Common configuration registers
+ ranges: true
+ clocks:
+ maxItems: 1
+ description: The SD/SDIO controller clock gate
+
+patternProperties:
+ "^sdhci@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ enum: [ aspeed,ast2400-sdhci, aspeed,ast2500-sdhci ]
+ reg:
+ maxItems: 1
+ description: The SDHCI registers
+ clocks:
+ maxItems: 1
+ description: The SD bus clock
+ interrupts:
+ maxItems: 1
+ description: The SD interrupt shared between both slots
+ required:
+ - compatible
+ - reg
+ - clocks
+ - interrupts
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - ranges
+ - clocks
+
+examples:
+ - |
+ #include <dt-bindings/clock/aspeed-clock.h>
+ sdc@1e740000 {
+ compatible = "aspeed,ast2500-sd-controller";
+ reg = <0x1e740000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x1e740000 0x10000>;
+ clocks = <&syscon ASPEED_CLK_GATE_SDCLK>;
+
+ sdhci0: sdhci@100 {
+ compatible = "aspeed,ast2500-sdhci";
+ reg = <0x100 0x100>;
+ interrupts = <26>;
+ sdhci,auto-cmd12;
+ clocks = <&syscon ASPEED_CLK_SDIO>;
+ };
+
+ sdhci1: sdhci@200 {
+ compatible = "aspeed,ast2500-sdhci";
+ reg = <0x200 0x100>;
+ interrupts = <26>;
+ sdhci,auto-cmd12;
+ clocks = <&syscon ASPEED_CLK_SDIO>;
+ };
+ };
--
2.20.1
^ permalink raw reply related
* [PATCH v2 2/2] mmc: Add support for the ASPEED SD controller
From: Andrew Jeffery @ 2019-07-12 3:32 UTC (permalink / raw)
To: linux-mmc
Cc: Andrew Jeffery, ulf.hansson, robh+dt, mark.rutland, joel,
adrian.hunter, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, ryanchen.aspeed
In-Reply-To: <20190712033214.24713-1-andrew@aj.id.au>
Add a minimal driver for ASPEED's SD controller, which exposes two
SDHCIs.
The ASPEED design implements a common register set for the SDHCIs, and
moves some of the standard configuration elements out to this common
area (e.g. 8-bit mode, and card detect configuration which is not
currently supported).
The SD controller has a dedicated hardware interrupt that is shared
between the slots. The common register set exposes information on which
slot triggered the interrupt; early revisions of the patch introduced an
irqchip for the register, but reality is it doesn't behave as an
irqchip, and the result fits awkwardly into the irqchip APIs. Instead
I've taken the simple approach of using the IRQ as a shared IRQ with
some minor performance impact for the second slot.
Ryan was the original author of the patch - I've taken his work and
massaged it to drop the irqchip support and rework the devicetree
integration. The driver has been smoke tested under qemu against a
minimal SD controller model and lightly tested on an ast2500-evb.
Signed-off-by: Ryan Chen <ryanchen.aspeed@gmail.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
---
In v2:
* Drop unnecesasry MODULE_DEVICE_TABLE()
* Rename sd-controller compatible
* Add IBM copyright
* Drop unnecesary data assignment in of match table entries
* Derive the slot from the SDHCI offset
drivers/mmc/host/Kconfig | 12 ++
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-of-aspeed.c | 326 +++++++++++++++++++++++++++++
3 files changed, 339 insertions(+)
create mode 100644 drivers/mmc/host/sdhci-of-aspeed.c
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 931770f17087..2bb5e1264b3d 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -154,6 +154,18 @@ config MMC_SDHCI_OF_ARASAN
If unsure, say N.
+config MMC_SDHCI_OF_ASPEED
+ tristate "SDHCI OF support for the ASPEED SDHCI controller"
+ depends on MMC_SDHCI_PLTFM
+ depends on OF
+ help
+ This selects the ASPEED Secure Digital Host Controller Interface.
+
+ If you have a controller with this interface, say Y or M here. You
+ also need to enable an appropriate bus interface.
+
+ If unsure, say N.
+
config MMC_SDHCI_OF_AT91
tristate "SDHCI OF support for the Atmel SDMMC controller"
depends on MMC_SDHCI_PLTFM
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 73578718f119..390ee162fe71 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o
+obj-$(CONFIG_MMC_SDHCI_OF_ASPEED) += sdhci-of-aspeed.o
obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c
new file mode 100644
index 000000000000..9528e43c257d
--- /dev/null
+++ b/drivers/mmc/host/sdhci-of-aspeed.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (C) 2019 ASPEED Technology Inc. */
+/* Copyright (C) 2019 IBM Corp. */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include "sdhci-pltfm.h"
+
+#define ASPEED_SDC_INFO 0x00
+#define ASPEED_SDC_S1MMC8 BIT(25)
+#define ASPEED_SDC_S0MMC8 BIT(24)
+
+struct aspeed_sdc {
+ struct clk *clk;
+ struct resource *res;
+
+ spinlock_t lock;
+ void __iomem *regs;
+};
+
+struct aspeed_sdhci {
+ struct aspeed_sdc *parent;
+ u32 width_mask;
+};
+
+static void aspeed_sdc_bus_width(struct aspeed_sdc *sdc,
+ struct aspeed_sdhci *sdhci, bool bus8)
+{
+ u32 info;
+
+ /* Set/clear 8 bit mode */
+ spin_lock(&sdc->lock);
+ info = readl(sdc->regs + ASPEED_SDC_INFO);
+ if (bus8)
+ info |= sdhci->width_mask;
+ else
+ info &= ~sdhci->width_mask;
+ writel(info, sdc->regs + ASPEED_SDC_INFO);
+ spin_unlock(&sdc->lock);
+}
+
+static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ unsigned long timeout;
+ int div;
+ u16 clk;
+
+ if (clock == host->clock)
+ return;
+
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+ if (clock == 0)
+ goto out;
+
+ for (div = 1; div < 256; div *= 2) {
+ if ((host->max_clk / div) <= clock)
+ break;
+ }
+ div >>= 1;
+
+ clk = div << SDHCI_DIVIDER_SHIFT;
+ clk |= SDHCI_CLOCK_INT_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ /* Wait max 20 ms */
+ timeout = 20;
+ while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+ & SDHCI_CLOCK_INT_STABLE)) {
+ if (timeout == 0) {
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ return;
+ }
+ timeout--;
+ mdelay(1);
+ }
+
+ clk |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+out:
+ host->clock = clock;
+}
+
+static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width)
+{
+ struct sdhci_pltfm_host *pltfm_priv;
+ struct aspeed_sdhci *aspeed_sdhci;
+ struct aspeed_sdc *aspeed_sdc;
+ u8 ctrl;
+
+ pltfm_priv = sdhci_priv(host);
+ aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv);
+ aspeed_sdc = aspeed_sdhci->parent;
+
+ /* Set/clear 8-bit mode */
+ aspeed_sdc_bus_width(aspeed_sdc, aspeed_sdhci,
+ width == MMC_BUS_WIDTH_8);
+
+ /* Set/clear 1 or 4 bit mode */
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ if (width == MMC_BUS_WIDTH_4)
+ ctrl |= SDHCI_CTRL_4BITBUS;
+ else
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
+static const struct sdhci_ops aspeed_sdhci_ops = {
+ .set_clock = aspeed_sdhci_set_clock,
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_bus_width = aspeed_sdhci_set_bus_width,
+ .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+ .reset = sdhci_reset,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static const struct sdhci_pltfm_data aspeed_sdc_pdata = {
+ .ops = &aspeed_sdhci_ops,
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+ .quirks2 = SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
+};
+
+static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev,
+ struct resource *res)
+{
+ resource_size_t delta;
+
+ if (!res || resource_type(res) != IORESOURCE_MEM)
+ return -EINVAL;
+
+ if (res->start < dev->parent->res->start)
+ return -EINVAL;
+
+ delta = res->start - dev->parent->res->start;
+ if (delta & (0x100 - 1))
+ return -EINVAL;
+
+ return (delta / 0x100) - 1;
+}
+
+static int aspeed_sdhci_probe(struct platform_device *pdev)
+{
+ struct sdhci_pltfm_host *pltfm_host;
+ struct aspeed_sdhci *dev;
+ struct sdhci_host *host;
+ struct resource *res;
+ int slot;
+ int ret;
+
+ host = sdhci_pltfm_init(pdev, &aspeed_sdc_pdata, sizeof(*dev));
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ pltfm_host = sdhci_priv(host);
+ dev = sdhci_pltfm_priv(pltfm_host);
+ dev->parent = dev_get_drvdata(pdev->dev.parent);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ slot = aspeed_sdhci_calculate_slot(dev, res);
+ if (slot < 0)
+ return slot;
+ dev_info(&pdev->dev, "Configuring for slot %d\n", slot);
+ dev->width_mask = !slot ? ASPEED_SDC_S0MMC8 : ASPEED_SDC_S1MMC8;
+
+ sdhci_get_of_property(pdev);
+
+ pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pltfm_host->clk))
+ return PTR_ERR(pltfm_host->clk);
+
+ ret = clk_prepare_enable(pltfm_host->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable SDIO clock\n");
+ goto err_pltfm_free;
+ }
+
+ ret = mmc_of_parse(host->mmc);
+ if (ret)
+ goto err_sdhci_add;
+
+ ret = sdhci_add_host(host);
+ if (ret)
+ goto err_sdhci_add;
+
+ return 0;
+
+err_sdhci_add:
+ clk_disable_unprepare(pltfm_host->clk);
+err_pltfm_free:
+ sdhci_pltfm_free(pdev);
+ return ret;
+}
+
+static int aspeed_sdhci_remove(struct platform_device *pdev)
+{
+ struct sdhci_pltfm_host *pltfm_host;
+ struct sdhci_host *host;
+ int dead;
+
+ host = platform_get_drvdata(pdev);
+ pltfm_host = sdhci_priv(host);
+
+ dead = readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff;
+
+ sdhci_remove_host(host, dead);
+
+ clk_disable_unprepare(pltfm_host->clk);
+
+ sdhci_pltfm_free(pdev);
+
+ return 0;
+}
+
+static const struct of_device_id aspeed_sdhci_of_match[] = {
+ { .compatible = "aspeed,ast2400-sdhci", },
+ { .compatible = "aspeed,ast2500-sdhci", },
+ { }
+};
+
+static struct platform_driver aspeed_sdhci_driver = {
+ .driver = {
+ .name = "sdhci-aspeed",
+ .of_match_table = aspeed_sdhci_of_match,
+ },
+ .probe = aspeed_sdhci_probe,
+ .remove = aspeed_sdhci_remove,
+};
+
+module_platform_driver(aspeed_sdhci_driver);
+
+static int aspeed_sdc_probe(struct platform_device *pdev)
+
+{
+ struct device_node *parent, *child;
+ struct aspeed_sdc *sdc;
+ int ret;
+
+ sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL);
+ if (!sdc)
+ return -ENOMEM;
+
+ spin_lock_init(&sdc->lock);
+
+ sdc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(sdc->clk))
+ return PTR_ERR(sdc->clk);
+
+ ret = clk_prepare_enable(sdc->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable SDCLK\n");
+ return ret;
+ }
+
+ sdc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sdc->regs = devm_ioremap_resource(&pdev->dev, sdc->res);
+ if (IS_ERR(sdc->regs)) {
+ ret = PTR_ERR(sdc->regs);
+ goto err_clk;
+ }
+
+ dev_set_drvdata(&pdev->dev, sdc);
+
+ parent = pdev->dev.of_node;
+ for_each_available_child_of_node(parent, child) {
+ struct platform_device *cpdev;
+
+ cpdev = of_platform_device_create(child, NULL, &pdev->dev);
+ if (IS_ERR(cpdev)) {
+ of_node_put(child);
+ ret = PTR_ERR(pdev);
+ goto err_clk;
+ }
+ }
+
+ return 0;
+
+err_clk:
+ clk_disable_unprepare(sdc->clk);
+ return ret;
+}
+
+static int aspeed_sdc_remove(struct platform_device *pdev)
+{
+ struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev);
+
+ clk_disable_unprepare(sdc->clk);
+
+ return 0;
+}
+
+static const struct of_device_id aspeed_sdc_of_match[] = {
+ { .compatible = "aspeed,ast2400-sd-controller", },
+ { .compatible = "aspeed,ast2500-sd-controller", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match);
+
+static struct platform_driver aspeed_sdc_driver = {
+ .driver = {
+ .name = "sd-controller-aspeed",
+ .pm = &sdhci_pltfm_pmops,
+ .of_match_table = aspeed_sdc_of_match,
+ },
+ .probe = aspeed_sdc_probe,
+ .remove = aspeed_sdc_remove,
+};
+
+module_platform_driver(aspeed_sdc_driver);
+
+MODULE_DESCRIPTION("Driver for the ASPEED SD/SDIO/SDHCI Controllers");
+MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
+MODULE_LICENSE("GPL v2");
--
2.20.1
^ permalink raw reply related
* [PATCH v9 0/8] EDAC drivers for Armada XP L2 and DDR
From: Chris Packham @ 2019-07-12 3:48 UTC (permalink / raw)
To: bp, robh+dt, mark.rutland, linux, patches, mchehab, james.morse,
jlu
Cc: devicetree, linux-arm-kernel, linux-edac, linux-kernel,
Chris Packham
Hi,
I still seem to be struggling to get this on anyone's radar.
The Reviews/Acks have been given so this should be good to go in via the ARM
tree as planned.
http://lists.infradead.org/pipermail/linux-arm-kernel/2017-August/525561.html
This series adds drivers for the L2 cache and DDR RAM ECC functionality as
found on the MV78230/MV78x60 SoCs. Jan has tested these changes with the
MV78460 (on a custom board with a DDR3 ECC DIMM), Chris has tested these
changes with 88F6820 and 98dx3236 (both a custom boards with fixed DDR3 + ECC).
Also contained in this series is an additional debugfs wrapper.
Compared to the previous v8 series this has been rebased against
v5.2-5628-g753c8d9b7d81 to avoid some conflicts related to debugfs API changes.
Compared to the previous v7 series this has been rebased against 5.1 requiring
some changes in the devicetree binding documentation.
Compared to the previous v6 series I've dropped the marvell,ecc-disable
property.
Compared to the previous v5 series I've split the dt-binding documentation into
its own patch and updated armada_xp_edac.c to use a SPDX license.
Compared to the previous v4 series I've added my s-o-b to some of Jan's
patches and rebased against v4.19.0.
Compared to the previous v3 series, the following changes have been made:
- Use shorter names for the AURORA ECC and parity registers
- Numerous formatting changes to edac/armada_xp.c (as requested by Boris)
- Added support for Armada-38x and 98dx3236 SoCs
Compared to the previous v2 series, the following changes have been made:
- Allocate EDAC structures later during probing and drop devres support
patches (requested by Boris)
- Make drvdata->width usage consistent according to the comment (suggested by
Chris)
Compared to the previous v1 series, the following changes have been made:
- Add the aurora-l2 register defines earlier in the series (suggested by
Russell King and Gregory CLEMENT )
- Changed the DT vendor prefix from "arm" to "marvell" for the ecc-enable/disable
properties on the aurora-l2 (suggested by Russell King)
- Fix some warnings reported by checkpatch
Compared to the original RFC series, the following changes have been made:
- Integrated Chris' patches for parity and ECC configuration via DT
- Merged the DDR RAM and L2 cache drivers (as requested by Boris, analogous
to fsl_ddr_edac.c and mpc85xx_edac.c)
- Added myself to MAINTAINERS (requested by Boris)
- L2 cache: Track the msg size and use snprintf (review comment by Chris)
- L2 cache: Split error injection from the check function (review comment by
Chris)
- DDR RAM: Allow 16 bit width in addition to 32 and 64 bit (review comment by
Chris)
- Use of_match_ptr() (review comments by Chris)
- Minor checkpatch cleanups
Chris Packham (4):
ARM: l2x0: support parity-enable/disable on aurora
dt-bindings: ARM: document marvell,ecc-enable binding
ARM: l2x0: add marvell,ecc-enable property for aurora
EDAC: armada_xp: Add support for more SoCs
Jan Luebbe (4):
ARM: aurora-l2: add prefix to MAX_RANGE_SIZE
ARM: aurora-l2: add defines for parity and ECC registers
EDAC: Add missing debugfs_create_x32 wrapper
EDAC: Add driver for the Marvell Armada XP SDRAM and L2 cache ECC
.../devicetree/bindings/arm/l2c2x0.yaml | 4 +
MAINTAINERS | 6 +
.../include/asm/hardware/cache-aurora-l2.h | 50 +-
arch/arm/mm/cache-l2x0.c | 16 +-
drivers/edac/Kconfig | 7 +
drivers/edac/Makefile | 1 +
drivers/edac/armada_xp_edac.c | 635 ++++++++++++++++++
drivers/edac/debugfs.c | 11 +
drivers/edac/edac_module.h | 4 +
9 files changed, 731 insertions(+), 3 deletions(-)
create mode 100644 drivers/edac/armada_xp_edac.c
--
2.22.0
^ permalink raw reply
* [PATCH v9 1/8] ARM: aurora-l2: add prefix to MAX_RANGE_SIZE
From: Chris Packham @ 2019-07-12 3:48 UTC (permalink / raw)
To: bp, robh+dt, mark.rutland, linux, patches, mchehab, james.morse,
jlu
Cc: devicetree, linux-arm-kernel, linux-edac, linux-kernel,
Gregory CLEMENT, Chris Packham
In-Reply-To: <20190712034904.5747-1-chris.packham@alliedtelesis.co.nz>
From: Jan Luebbe <jlu@pengutronix.de>
The macro name is too generic, so add a AURORA_ prefix.
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Reviewed-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
arch/arm/include/asm/hardware/cache-aurora-l2.h | 2 +-
arch/arm/mm/cache-l2x0.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/hardware/cache-aurora-l2.h b/arch/arm/include/asm/hardware/cache-aurora-l2.h
index c86124769831..dc5c479ec4c3 100644
--- a/arch/arm/include/asm/hardware/cache-aurora-l2.h
+++ b/arch/arm/include/asm/hardware/cache-aurora-l2.h
@@ -41,7 +41,7 @@
#define AURORA_ACR_FORCE_WRITE_THRO_POLICY \
(2 << AURORA_ACR_FORCE_WRITE_POLICY_OFFSET)
-#define MAX_RANGE_SIZE 1024
+#define AURORA_MAX_RANGE_SIZE 1024
#define AURORA_WAY_SIZE_SHIFT 2
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 428d08718107..83b733a1f1e6 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -1352,8 +1352,8 @@ static unsigned long aurora_range_end(unsigned long start, unsigned long end)
* since cache range operations stall the CPU pipeline
* until completion.
*/
- if (end > start + MAX_RANGE_SIZE)
- end = start + MAX_RANGE_SIZE;
+ if (end > start + AURORA_MAX_RANGE_SIZE)
+ end = start + AURORA_MAX_RANGE_SIZE;
/*
* Cache range operations can't straddle a page boundary.
--
2.22.0
^ permalink raw reply related
* [PATCH v9 2/8] ARM: aurora-l2: add defines for parity and ECC registers
From: Chris Packham @ 2019-07-12 3:48 UTC (permalink / raw)
To: bp, robh+dt, mark.rutland, linux, patches, mchehab, james.morse,
jlu
Cc: devicetree, linux-arm-kernel, linux-edac, linux-kernel,
Chris Packham
In-Reply-To: <20190712034904.5747-1-chris.packham@alliedtelesis.co.nz>
From: Jan Luebbe <jlu@pengutronix.de>
These defines will be used by subsequent patches to add support for the
parity check and error correction functionality in the Aurora L2 cache
controller.
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
.../include/asm/hardware/cache-aurora-l2.h | 48 +++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/arch/arm/include/asm/hardware/cache-aurora-l2.h b/arch/arm/include/asm/hardware/cache-aurora-l2.h
index dc5c479ec4c3..39769ffa0051 100644
--- a/arch/arm/include/asm/hardware/cache-aurora-l2.h
+++ b/arch/arm/include/asm/hardware/cache-aurora-l2.h
@@ -31,6 +31,9 @@
#define AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU \
(3 << AURORA_ACR_REPLACEMENT_OFFSET)
+#define AURORA_ACR_PARITY_EN (1 << 21)
+#define AURORA_ACR_ECC_EN (1 << 20)
+
#define AURORA_ACR_FORCE_WRITE_POLICY_OFFSET 0
#define AURORA_ACR_FORCE_WRITE_POLICY_MASK \
(0x3 << AURORA_ACR_FORCE_WRITE_POLICY_OFFSET)
@@ -41,6 +44,51 @@
#define AURORA_ACR_FORCE_WRITE_THRO_POLICY \
(2 << AURORA_ACR_FORCE_WRITE_POLICY_OFFSET)
+#define AURORA_ERR_CNT_REG 0x600
+#define AURORA_ERR_ATTR_CAP_REG 0x608
+#define AURORA_ERR_ADDR_CAP_REG 0x60c
+#define AURORA_ERR_WAY_CAP_REG 0x610
+#define AURORA_ERR_INJECT_CTL_REG 0x614
+#define AURORA_ERR_INJECT_MASK_REG 0x618
+
+#define AURORA_ERR_CNT_CLR_OFFSET 31
+#define AURORA_ERR_CNT_CLR \
+ (0x1 << AURORA_ERR_CNT_CLR_OFFSET)
+#define AURORA_ERR_CNT_UE_OFFSET 16
+#define AURORA_ERR_CNT_UE_MASK \
+ (0x7fff << AURORA_ERR_CNT_UE_OFFSET)
+#define AURORA_ERR_CNT_CE_OFFSET 0
+#define AURORA_ERR_CNT_CE_MASK \
+ (0xffff << AURORA_ERR_CNT_CE_OFFSET)
+
+#define AURORA_ERR_ATTR_SRC_OFF 16
+#define AURORA_ERR_ATTR_SRC_MSK \
+ (0x7 << AURORA_ERR_ATTR_SRC_OFF)
+#define AURORA_ERR_ATTR_TXN_OFF 12
+#define AURORA_ERR_ATTR_TXN_MSK \
+ (0xf << AURORA_ERR_ATTR_TXN_OFF)
+#define AURORA_ERR_ATTR_ERR_OFF 8
+#define AURORA_ERR_ATTR_ERR_MSK \
+ (0x3 << AURORA_ERR_ATTR_ERR_OFF)
+#define AURORA_ERR_ATTR_CAP_VALID_OFF 0
+#define AURORA_ERR_ATTR_CAP_VALID \
+ (0x1 << AURORA_ERR_ATTR_CAP_VALID_OFF)
+
+#define AURORA_ERR_ADDR_CAP_ADDR_MASK 0xffffffe0
+
+#define AURORA_ERR_WAY_IDX_OFF 8
+#define AURORA_ERR_WAY_IDX_MSK \
+ (0xfff << AURORA_ERR_WAY_IDX_OFF)
+#define AURORA_ERR_WAY_CAP_WAY_OFFSET 1
+#define AURORA_ERR_WAY_CAP_WAY_MASK \
+ (0xf << AURORA_ERR_WAY_CAP_WAY_OFFSET)
+
+#define AURORA_ERR_INJECT_CTL_ADDR_MASK 0xfffffff0
+#define AURORA_ERR_ATTR_TXN_OFF 12
+#define AURORA_ERR_INJECT_CTL_EN_MASK 0x3
+#define AURORA_ERR_INJECT_CTL_EN_PARITY 0x2
+#define AURORA_ERR_INJECT_CTL_EN_ECC 0x1
+
#define AURORA_MAX_RANGE_SIZE 1024
#define AURORA_WAY_SIZE_SHIFT 2
--
2.22.0
^ permalink raw reply related
* [PATCH v9 3/8] ARM: l2x0: support parity-enable/disable on aurora
From: Chris Packham @ 2019-07-12 3:48 UTC (permalink / raw)
To: bp, robh+dt, mark.rutland, linux, patches, mchehab, james.morse,
jlu
Cc: devicetree, linux-arm-kernel, linux-edac, linux-kernel,
Chris Packham
In-Reply-To: <20190712034904.5747-1-chris.packham@alliedtelesis.co.nz>
The aurora cache on the Marvell Armada-XP SoC supports the same tag
parity features as the other l2x0 cache implementations.
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
[jlu@pengutronix.de: use aurora specific define AURORA_ACR_PARITY_EN]
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
arch/arm/mm/cache-l2x0.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 83b733a1f1e6..46a616ec6b0c 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -1493,6 +1493,13 @@ static void __init aurora_of_parse(const struct device_node *np,
mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK;
}
+ if (of_property_read_bool(np, "arm,parity-enable")) {
+ mask |= AURORA_ACR_PARITY_EN;
+ val |= AURORA_ACR_PARITY_EN;
+ } else if (of_property_read_bool(np, "arm,parity-disable")) {
+ mask |= AURORA_ACR_PARITY_EN;
+ }
+
*aux_val &= ~mask;
*aux_val |= val;
*aux_mask &= ~mask;
--
2.22.0
^ permalink raw reply related
* [PATCH v9 4/8] dt-bindings: ARM: document marvell,ecc-enable binding
From: Chris Packham @ 2019-07-12 3:49 UTC (permalink / raw)
To: bp, robh+dt, mark.rutland, linux, patches, mchehab, james.morse,
jlu
Cc: devicetree, linux-arm-kernel, linux-edac, linux-kernel,
Chris Packham, Rob Herring
In-Reply-To: <20190712034904.5747-1-chris.packham@alliedtelesis.co.nz>
Add documentation for the marvell,ecc-enable properties which can be
used to enable ECC on the Marvell aurora cache.
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Notes:
Changes in v7:
- remove marvell,ecc-disable
Changes in v6:
- new (split binding doc from implementation).
Documentation/devicetree/bindings/arm/l2c2x0.yaml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/l2c2x0.yaml b/Documentation/devicetree/bindings/arm/l2c2x0.yaml
index bfc5c185561c..913a8cd8b2c0 100644
--- a/Documentation/devicetree/bindings/arm/l2c2x0.yaml
+++ b/Documentation/devicetree/bindings/arm/l2c2x0.yaml
@@ -176,6 +176,10 @@ properties:
description: disable parity checking on the L2 cache (L220 or PL310).
type: boolean
+ marvell,ecc-enable:
+ description: enable ECC protection on the L2 cache
+ type: boolean
+
arm,outer-sync-disable:
description: disable the outer sync operation on the L2 cache.
Some core tiles, especially ARM PB11MPCore have a faulty L220 cache that
--
2.22.0
^ permalink raw reply related
* [PATCH v9 5/8] ARM: l2x0: add marvell,ecc-enable property for aurora
From: Chris Packham @ 2019-07-12 3:49 UTC (permalink / raw)
To: bp, robh+dt, mark.rutland, linux, patches, mchehab, james.morse,
jlu
Cc: devicetree, linux-arm-kernel, linux-edac, linux-kernel,
Chris Packham
In-Reply-To: <20190712034904.5747-1-chris.packham@alliedtelesis.co.nz>
The aurora cache on the Marvell Armada-XP SoC supports ECC protection
for the L2 data arrays. Add a "marvell,ecc-enable" device tree property
which can be used to enable this.
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
[jlu@pengutronix.de: use aurora specific define AURORA_ACR_ECC_EN]
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
Notes:
Changes in v7:
- remove marvell,ecc-disable
arch/arm/mm/cache-l2x0.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 46a616ec6b0c..12c26eb88afb 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -1493,6 +1493,11 @@ static void __init aurora_of_parse(const struct device_node *np,
mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK;
}
+ if (of_property_read_bool(np, "marvell,ecc-enable")) {
+ mask |= AURORA_ACR_ECC_EN;
+ val |= AURORA_ACR_ECC_EN;
+ }
+
if (of_property_read_bool(np, "arm,parity-enable")) {
mask |= AURORA_ACR_PARITY_EN;
val |= AURORA_ACR_PARITY_EN;
--
2.22.0
^ permalink raw reply related
* [PATCH v9 6/8] EDAC: Add missing debugfs_create_x32 wrapper
From: Chris Packham @ 2019-07-12 3:49 UTC (permalink / raw)
To: bp, robh+dt, mark.rutland, linux, patches, mchehab, james.morse,
jlu
Cc: devicetree, linux-arm-kernel, linux-edac, linux-kernel,
Borislav Petkov, Chris Packham
In-Reply-To: <20190712034904.5747-1-chris.packham@alliedtelesis.co.nz>
From: Jan Luebbe <jlu@pengutronix.de>
We already have wrappers for x8 and x16, so add the missing x32 one.
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Reviewed-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
Notes:
Changes in v9:
- Adapt debugfs_create_x32 to account for recent changes to debugfs apis
drivers/edac/debugfs.c | 11 +++++++++++
drivers/edac/edac_module.h | 4 ++++
2 files changed, 15 insertions(+)
diff --git a/drivers/edac/debugfs.c b/drivers/edac/debugfs.c
index 1f943599a8ac..4804332d9946 100644
--- a/drivers/edac/debugfs.c
+++ b/drivers/edac/debugfs.c
@@ -138,3 +138,14 @@ void edac_debugfs_create_x16(const char *name, umode_t mode,
debugfs_create_x16(name, mode, parent, value);
}
EXPORT_SYMBOL_GPL(edac_debugfs_create_x16);
+
+/* Wrapper for debugfs_create_x32() */
+void edac_debugfs_create_x32(const char *name, umode_t mode,
+ struct dentry *parent, u32 *value)
+{
+ if (!parent)
+ parent = edac_debugfs;
+
+ debugfs_create_x32(name, mode, parent, value);
+}
+EXPORT_SYMBOL_GPL(edac_debugfs_create_x32);
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index b2f59ee76c22..388427d378b1 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -82,6 +82,8 @@ void edac_debugfs_create_x8(const char *name, umode_t mode,
struct dentry *parent, u8 *value);
void edac_debugfs_create_x16(const char *name, umode_t mode,
struct dentry *parent, u16 *value);
+void edac_debugfs_create_x32(const char *name, umode_t mode,
+ struct dentry *parent, u32 *value);
#else
static inline void edac_debugfs_init(void) { }
static inline void edac_debugfs_exit(void) { }
@@ -96,6 +98,8 @@ static inline void edac_debugfs_create_x8(const char *name, umode_t mode,
struct dentry *parent, u8 *value) { }
static inline void edac_debugfs_create_x16(const char *name, umode_t mode,
struct dentry *parent, u16 *value) { }
+static inline void edac_debugfs_create_x32(const char *name, umode_t mode,
+ struct dentry *parent, u32 *value) { }
#endif
/*
--
2.22.0
^ permalink raw reply related
* [PATCH v9 7/8] EDAC: Add driver for the Marvell Armada XP SDRAM and L2 cache ECC
From: Chris Packham @ 2019-07-12 3:49 UTC (permalink / raw)
To: bp, robh+dt, mark.rutland, linux, patches, mchehab, james.morse,
jlu
Cc: devicetree, linux-arm-kernel, linux-edac, linux-kernel,
Chris Packham, Borislav Petkov
In-Reply-To: <20190712034904.5747-1-chris.packham@alliedtelesis.co.nz>
From: Jan Luebbe <jlu@pengutronix.de>
Add support for the ECC functionality as found in the DDR RAM and L2
cache controllers on the MV78230/MV78x60 SoCs. This driver has been
tested on the MV78460 (on a custom board with a DDR3 ECC DIMM).
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
[cp use SPDX license]
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Reviewed-by: Borislav Petkov <bp@suse.de>
---
MAINTAINERS | 6 +
drivers/edac/Kconfig | 7 +
drivers/edac/Makefile | 1 +
drivers/edac/armada_xp_edac.c | 630 ++++++++++++++++++++++++++++++++++
4 files changed, 644 insertions(+)
create mode 100644 drivers/edac/armada_xp_edac.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 618e4979960b..d6cf0771c998 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5697,6 +5697,12 @@ L: linux-edac@vger.kernel.org
S: Maintained
F: drivers/edac/amd64_edac*
+EDAC-ARMADA
+M: Jan Luebbe <jlu@pengutronix.de>
+L: linux-edac@vger.kernel.org
+S: Maintained
+F: drivers/edac/armada_xp_*
+
EDAC-AST2500
M: Stefan Schaeckeler <sschaeck@cisco.com>
S: Supported
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 200c04ce5b0e..39c58b37b889 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -466,6 +466,13 @@ config EDAC_SIFIVE
help
Support for error detection and correction on the SiFive SoCs.
+config EDAC_ARMADA_XP
+ bool "Marvell Armada XP DDR and L2 Cache ECC"
+ depends on MACH_MVEBU_V7
+ help
+ Support for error correction and detection on the Marvell Aramada XP
+ DDR RAM and L2 cache controllers.
+
config EDAC_SYNOPSYS
tristate "Synopsys DDR Memory Controller"
depends on ARCH_ZYNQ || ARCH_ZYNQMP
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 165ca65e1a3a..7b6348339a3b 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_EDAC_THUNDERX) += thunderx_edac.o
obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o
obj-$(CONFIG_EDAC_SIFIVE) += sifive_edac.o
+obj-$(CONFIG_EDAC_ARMADA_XP) += armada_xp_edac.o
obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
obj-$(CONFIG_EDAC_TI) += ti_edac.o
diff --git a/drivers/edac/armada_xp_edac.c b/drivers/edac/armada_xp_edac.c
new file mode 100644
index 000000000000..3759a4fbbdee
--- /dev/null
+++ b/drivers/edac/armada_xp_edac.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Pengutronix, Jan Luebbe <kernel@pengutronix.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/edac.h>
+#include <linux/of_platform.h>
+
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/cache-aurora-l2.h>
+
+#include "edac_mc.h"
+#include "edac_device.h"
+#include "edac_module.h"
+
+/************************ EDAC MC (DDR RAM) ********************************/
+
+#define SDRAM_NUM_CS 4
+
+#define SDRAM_CONFIG_REG 0x0
+#define SDRAM_CONFIG_ECC_MASK BIT(18)
+#define SDRAM_CONFIG_REGISTERED_MASK BIT(17)
+#define SDRAM_CONFIG_BUS_WIDTH_MASK BIT(15)
+
+#define SDRAM_ADDR_CTRL_REG 0x10
+#define SDRAM_ADDR_CTRL_SIZE_HIGH_OFFSET(cs) (20+cs)
+#define SDRAM_ADDR_CTRL_SIZE_HIGH_MASK(cs) (0x1 << SDRAM_ADDR_CTRL_SIZE_HIGH_OFFSET(cs))
+#define SDRAM_ADDR_CTRL_ADDR_SEL_MASK(cs) BIT(16+cs)
+#define SDRAM_ADDR_CTRL_SIZE_LOW_OFFSET(cs) (cs*4+2)
+#define SDRAM_ADDR_CTRL_SIZE_LOW_MASK(cs) (0x3 << SDRAM_ADDR_CTRL_SIZE_LOW_OFFSET(cs))
+#define SDRAM_ADDR_CTRL_STRUCT_OFFSET(cs) (cs*4)
+#define SDRAM_ADDR_CTRL_STRUCT_MASK(cs) (0x3 << SDRAM_ADDR_CTRL_STRUCT_OFFSET(cs))
+
+#define SDRAM_ERR_DATA_H_REG 0x40
+#define SDRAM_ERR_DATA_L_REG 0x44
+
+#define SDRAM_ERR_RECV_ECC_REG 0x48
+#define SDRAM_ERR_RECV_ECC_VALUE_MASK 0xff
+
+#define SDRAM_ERR_CALC_ECC_REG 0x4c
+#define SDRAM_ERR_CALC_ECC_ROW_OFFSET 8
+#define SDRAM_ERR_CALC_ECC_ROW_MASK (0xffff << SDRAM_ERR_CALC_ECC_ROW_OFFSET)
+#define SDRAM_ERR_CALC_ECC_VALUE_MASK 0xff
+
+#define SDRAM_ERR_ADDR_REG 0x50
+#define SDRAM_ERR_ADDR_BANK_OFFSET 23
+#define SDRAM_ERR_ADDR_BANK_MASK (0x7 << SDRAM_ERR_ADDR_BANK_OFFSET)
+#define SDRAM_ERR_ADDR_COL_OFFSET 8
+#define SDRAM_ERR_ADDR_COL_MASK (0x7fff << SDRAM_ERR_ADDR_COL_OFFSET)
+#define SDRAM_ERR_ADDR_CS_OFFSET 1
+#define SDRAM_ERR_ADDR_CS_MASK (0x3 << SDRAM_ERR_ADDR_CS_OFFSET)
+#define SDRAM_ERR_ADDR_TYPE_MASK BIT(0)
+
+#define SDRAM_ERR_CTRL_REG 0x54
+#define SDRAM_ERR_CTRL_THR_OFFSET 16
+#define SDRAM_ERR_CTRL_THR_MASK (0xff << SDRAM_ERR_CTRL_THR_OFFSET)
+#define SDRAM_ERR_CTRL_PROP_MASK BIT(9)
+
+#define SDRAM_ERR_SBE_COUNT_REG 0x58
+#define SDRAM_ERR_DBE_COUNT_REG 0x5c
+
+#define SDRAM_ERR_CAUSE_ERR_REG 0xd0
+#define SDRAM_ERR_CAUSE_MSG_REG 0xd8
+#define SDRAM_ERR_CAUSE_DBE_MASK BIT(1)
+#define SDRAM_ERR_CAUSE_SBE_MASK BIT(0)
+
+#define SDRAM_RANK_CTRL_REG 0x1e0
+#define SDRAM_RANK_CTRL_EXIST_MASK(cs) BIT(cs)
+
+struct axp_mc_drvdata {
+ void __iomem *base;
+ /* width in bytes */
+ unsigned int width;
+ /* bank interleaving */
+ bool cs_addr_sel[SDRAM_NUM_CS];
+
+ char msg[128];
+};
+
+/* derived from "DRAM Address Multiplexing" in the ARAMDA XP Functional Spec */
+static uint32_t axp_mc_calc_address(struct axp_mc_drvdata *drvdata,
+ uint8_t cs, uint8_t bank, uint16_t row,
+ uint16_t col)
+{
+ if (drvdata->width == 8) {
+ /* 64 bit */
+ if (drvdata->cs_addr_sel[cs])
+ /* bank interleaved */
+ return (((row & 0xfff8) << 16) |
+ ((bank & 0x7) << 16) |
+ ((row & 0x7) << 13) |
+ ((col & 0x3ff) << 3));
+ else
+ return (((row & 0xffff << 16) |
+ ((bank & 0x7) << 13) |
+ ((col & 0x3ff)) << 3));
+ } else if (drvdata->width == 4) {
+ /* 32 bit */
+ if (drvdata->cs_addr_sel[cs])
+ /* bank interleaved */
+ return (((row & 0xfff0) << 15) |
+ ((bank & 0x7) << 16) |
+ ((row & 0xf) << 12) |
+ ((col & 0x3ff) << 2));
+ else
+ return (((row & 0xffff << 15) |
+ ((bank & 0x7) << 12) |
+ ((col & 0x3ff)) << 2));
+ } else {
+ /* 16 bit */
+ if (drvdata->cs_addr_sel[cs])
+ /* bank interleaved */
+ return (((row & 0xffe0) << 14) |
+ ((bank & 0x7) << 16) |
+ ((row & 0x1f) << 11) |
+ ((col & 0x3ff) << 1));
+ else
+ return (((row & 0xffff << 14) |
+ ((bank & 0x7) << 11) |
+ ((col & 0x3ff)) << 1));
+ }
+}
+
+static void axp_mc_check(struct mem_ctl_info *mci)
+{
+ struct axp_mc_drvdata *drvdata = mci->pvt_info;
+ uint32_t data_h, data_l, recv_ecc, calc_ecc, addr;
+ uint32_t cnt_sbe, cnt_dbe, cause_err, cause_msg;
+ uint32_t row_val, col_val, bank_val, addr_val;
+ uint8_t syndrome_val, cs_val;
+ char *msg = drvdata->msg;
+
+ data_h = readl(drvdata->base + SDRAM_ERR_DATA_H_REG);
+ data_l = readl(drvdata->base + SDRAM_ERR_DATA_L_REG);
+ recv_ecc = readl(drvdata->base + SDRAM_ERR_RECV_ECC_REG);
+ calc_ecc = readl(drvdata->base + SDRAM_ERR_CALC_ECC_REG);
+ addr = readl(drvdata->base + SDRAM_ERR_ADDR_REG);
+ cnt_sbe = readl(drvdata->base + SDRAM_ERR_SBE_COUNT_REG);
+ cnt_dbe = readl(drvdata->base + SDRAM_ERR_DBE_COUNT_REG);
+ cause_err = readl(drvdata->base + SDRAM_ERR_CAUSE_ERR_REG);
+ cause_msg = readl(drvdata->base + SDRAM_ERR_CAUSE_MSG_REG);
+
+ /* clear cause registers */
+ writel(~(SDRAM_ERR_CAUSE_DBE_MASK | SDRAM_ERR_CAUSE_SBE_MASK),
+ drvdata->base + SDRAM_ERR_CAUSE_ERR_REG);
+ writel(~(SDRAM_ERR_CAUSE_DBE_MASK | SDRAM_ERR_CAUSE_SBE_MASK),
+ drvdata->base + SDRAM_ERR_CAUSE_MSG_REG);
+
+ /* clear error counter registers */
+ if (cnt_sbe)
+ writel(0, drvdata->base + SDRAM_ERR_SBE_COUNT_REG);
+ if (cnt_dbe)
+ writel(0, drvdata->base + SDRAM_ERR_DBE_COUNT_REG);
+
+ if (!cnt_sbe && !cnt_dbe)
+ return;
+
+ if (!(addr & SDRAM_ERR_ADDR_TYPE_MASK)) {
+ if (cnt_sbe)
+ cnt_sbe--;
+ else
+ dev_warn(mci->pdev, "inconsistent SBE count detected");
+ } else {
+ if (cnt_dbe)
+ cnt_dbe--;
+ else
+ dev_warn(mci->pdev, "inconsistent DBE count detected");
+ }
+
+ /* report earlier errors */
+ if (cnt_sbe)
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+ cnt_sbe, /* error count */
+ 0, 0, 0, /* pfn, offset, syndrome */
+ -1, -1, -1, /* top, mid, low layer */
+ mci->ctl_name,
+ "details unavailable (multiple errors)");
+ if (cnt_dbe)
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+ cnt_sbe, /* error count */
+ 0, 0, 0, /* pfn, offset, syndrome */
+ -1, -1, -1, /* top, mid, low layer */
+ mci->ctl_name,
+ "details unavailable (multiple errors)");
+
+ /* report details for most recent error */
+ cs_val = (addr & SDRAM_ERR_ADDR_CS_MASK) >> SDRAM_ERR_ADDR_CS_OFFSET;
+ bank_val = (addr & SDRAM_ERR_ADDR_BANK_MASK) >> SDRAM_ERR_ADDR_BANK_OFFSET;
+ row_val = (calc_ecc & SDRAM_ERR_CALC_ECC_ROW_MASK) >> SDRAM_ERR_CALC_ECC_ROW_OFFSET;
+ col_val = (addr & SDRAM_ERR_ADDR_COL_MASK) >> SDRAM_ERR_ADDR_COL_OFFSET;
+ syndrome_val = (recv_ecc ^ calc_ecc) & 0xff;
+ addr_val = axp_mc_calc_address(drvdata, cs_val, bank_val, row_val,
+ col_val);
+ msg += sprintf(msg, "row=0x%04x ", row_val); /* 11 chars */
+ msg += sprintf(msg, "bank=0x%x ", bank_val); /* 9 chars */
+ msg += sprintf(msg, "col=0x%04x ", col_val); /* 11 chars */
+ msg += sprintf(msg, "cs=%d", cs_val); /* 4 chars */
+
+ if (!(addr & SDRAM_ERR_ADDR_TYPE_MASK)) {
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+ 1, /* error count */
+ addr_val >> PAGE_SHIFT,
+ addr_val & ~PAGE_MASK,
+ syndrome_val,
+ cs_val, -1, -1, /* top, mid, low layer */
+ mci->ctl_name, drvdata->msg);
+ } else {
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+ 1, /* error count */
+ addr_val >> PAGE_SHIFT,
+ addr_val & ~PAGE_MASK,
+ syndrome_val,
+ cs_val, -1, -1, /* top, mid, low layer */
+ mci->ctl_name, drvdata->msg);
+ }
+}
+
+static void axp_mc_read_config(struct mem_ctl_info *mci)
+{
+ struct axp_mc_drvdata *drvdata = mci->pvt_info;
+ uint32_t config, addr_ctrl, rank_ctrl;
+ unsigned int i, cs_struct, cs_size;
+ struct dimm_info *dimm;
+
+ config = readl(drvdata->base + SDRAM_CONFIG_REG);
+ if (config & SDRAM_CONFIG_BUS_WIDTH_MASK)
+ /* 64 bit */
+ drvdata->width = 8;
+ else
+ /* 32 bit */
+ drvdata->width = 4;
+
+ addr_ctrl = readl(drvdata->base + SDRAM_ADDR_CTRL_REG);
+ rank_ctrl = readl(drvdata->base + SDRAM_RANK_CTRL_REG);
+ for (i = 0; i < SDRAM_NUM_CS; i++) {
+ dimm = mci->dimms[i];
+
+ if (!(rank_ctrl & SDRAM_RANK_CTRL_EXIST_MASK(i)))
+ continue;
+
+ drvdata->cs_addr_sel[i] =
+ !!(addr_ctrl & SDRAM_ADDR_CTRL_ADDR_SEL_MASK(i));
+
+ cs_struct = (addr_ctrl & SDRAM_ADDR_CTRL_STRUCT_MASK(i)) >> SDRAM_ADDR_CTRL_STRUCT_OFFSET(i);
+ cs_size = ((addr_ctrl & SDRAM_ADDR_CTRL_SIZE_HIGH_MASK(i)) >> (SDRAM_ADDR_CTRL_SIZE_HIGH_OFFSET(i) - 2) |
+ ((addr_ctrl & SDRAM_ADDR_CTRL_SIZE_LOW_MASK(i)) >> SDRAM_ADDR_CTRL_SIZE_LOW_OFFSET(i)));
+
+ switch (cs_size) {
+ case 0: /* 2GBit */
+ dimm->nr_pages = 524288;
+ break;
+ case 1: /* 256MBit */
+ dimm->nr_pages = 65536;
+ break;
+ case 2: /* 512MBit */
+ dimm->nr_pages = 131072;
+ break;
+ case 3: /* 1GBit */
+ dimm->nr_pages = 262144;
+ break;
+ case 4: /* 4GBit */
+ dimm->nr_pages = 1048576;
+ break;
+ case 5: /* 8GBit */
+ dimm->nr_pages = 2097152;
+ break;
+ }
+ dimm->grain = 8;
+ dimm->dtype = cs_struct ? DEV_X16 : DEV_X8;
+ dimm->mtype = (config & SDRAM_CONFIG_REGISTERED_MASK) ?
+ MEM_RDDR3 : MEM_DDR3;
+ dimm->edac_mode = EDAC_SECDED;
+ }
+}
+
+static const struct of_device_id axp_mc_of_match[] = {
+ {.compatible = "marvell,armada-xp-sdram-controller",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, axp_mc_of_match);
+
+static int axp_mc_probe(struct platform_device *pdev)
+{
+ struct axp_mc_drvdata *drvdata;
+ struct edac_mc_layer layers[1];
+ const struct of_device_id *id;
+ struct mem_ctl_info *mci;
+ struct resource *r;
+ void __iomem *base;
+ uint32_t config;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "Unable to get mem resource\n");
+ return -ENODEV;
+ }
+
+ base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(base)) {
+ dev_err(&pdev->dev, "Unable to map regs\n");
+ return PTR_ERR(base);
+ }
+
+ config = readl(base + SDRAM_CONFIG_REG);
+ if (!(config & SDRAM_CONFIG_ECC_MASK)) {
+ dev_warn(&pdev->dev, "SDRAM ECC is not enabled");
+ return -EINVAL;
+ }
+
+ layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+ layers[0].size = SDRAM_NUM_CS;
+ layers[0].is_virt_csrow = true;
+
+ mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*drvdata));
+ if (!mci)
+ return -ENOMEM;
+
+ drvdata = mci->pvt_info;
+ drvdata->base = base;
+ mci->pdev = &pdev->dev;
+ platform_set_drvdata(pdev, mci);
+
+ id = of_match_device(axp_mc_of_match, &pdev->dev);
+ mci->edac_check = axp_mc_check;
+ mci->mtype_cap = MEM_FLAG_DDR3;
+ mci->edac_cap = EDAC_FLAG_SECDED;
+ mci->mod_name = pdev->dev.driver->name;
+ mci->ctl_name = id ? id->compatible : "unknown";
+ mci->dev_name = dev_name(&pdev->dev);
+ mci->scrub_mode = SCRUB_NONE;
+
+ axp_mc_read_config(mci);
+
+ /* configure SBE threshold */
+ /* it seems that SBEs are not captured otherwise */
+ writel(1 << SDRAM_ERR_CTRL_THR_OFFSET, drvdata->base + SDRAM_ERR_CTRL_REG);
+
+ /* clear cause registers */
+ writel(~(SDRAM_ERR_CAUSE_DBE_MASK | SDRAM_ERR_CAUSE_SBE_MASK), drvdata->base + SDRAM_ERR_CAUSE_ERR_REG);
+ writel(~(SDRAM_ERR_CAUSE_DBE_MASK | SDRAM_ERR_CAUSE_SBE_MASK), drvdata->base + SDRAM_ERR_CAUSE_MSG_REG);
+
+ /* clear counter registers */
+ writel(0, drvdata->base + SDRAM_ERR_SBE_COUNT_REG);
+ writel(0, drvdata->base + SDRAM_ERR_DBE_COUNT_REG);
+
+ if (edac_mc_add_mc(mci)) {
+ edac_mc_free(mci);
+ return -EINVAL;
+ }
+ edac_op_state = EDAC_OPSTATE_POLL;
+
+ return 0;
+}
+
+static int axp_mc_remove(struct platform_device *pdev)
+{
+ struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+ edac_mc_del_mc(&pdev->dev);
+ edac_mc_free(mci);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver axp_mc_driver = {
+ .probe = axp_mc_probe,
+ .remove = axp_mc_remove,
+ .driver = {
+ .name = "armada_xp_mc_edac",
+ .of_match_table = of_match_ptr(axp_mc_of_match),
+ },
+};
+
+/************************ EDAC Device (L2 Cache) ***************************/
+
+struct aurora_l2_drvdata {
+ void __iomem *base;
+
+ char msg[128];
+
+ /* error injection via debugfs */
+ uint32_t inject_addr;
+ uint32_t inject_mask;
+ uint8_t inject_ctl;
+
+ struct dentry *debugfs;
+};
+
+#ifdef CONFIG_EDAC_DEBUG
+static void aurora_l2_inject(struct aurora_l2_drvdata *drvdata)
+{
+ drvdata->inject_addr &= AURORA_ERR_INJECT_CTL_ADDR_MASK;
+ drvdata->inject_ctl &= AURORA_ERR_INJECT_CTL_EN_MASK;
+ writel(0, drvdata->base + AURORA_ERR_INJECT_CTL_REG);
+ writel(drvdata->inject_mask, drvdata->base + AURORA_ERR_INJECT_MASK_REG);
+ writel(drvdata->inject_addr | drvdata->inject_ctl, drvdata->base + AURORA_ERR_INJECT_CTL_REG);
+}
+#endif
+
+static void aurora_l2_check(struct edac_device_ctl_info *dci)
+{
+ struct aurora_l2_drvdata *drvdata = dci->pvt_info;
+ uint32_t cnt, src, txn, err, attr_cap, addr_cap, way_cap;
+ unsigned int cnt_ce, cnt_ue;
+ char *msg = drvdata->msg;
+ size_t size = sizeof(drvdata->msg);
+ size_t len = 0;
+
+ cnt = readl(drvdata->base + AURORA_ERR_CNT_REG);
+ attr_cap = readl(drvdata->base + AURORA_ERR_ATTR_CAP_REG);
+ addr_cap = readl(drvdata->base + AURORA_ERR_ADDR_CAP_REG);
+ way_cap = readl(drvdata->base + AURORA_ERR_WAY_CAP_REG);
+
+ cnt_ce = (cnt & AURORA_ERR_CNT_CE_MASK) >> AURORA_ERR_CNT_CE_OFFSET;
+ cnt_ue = (cnt & AURORA_ERR_CNT_UE_MASK) >> AURORA_ERR_CNT_UE_OFFSET;
+ /* clear error counter registers */
+ if (cnt_ce || cnt_ue)
+ writel(AURORA_ERR_CNT_CLR, drvdata->base + AURORA_ERR_CNT_REG);
+
+ if (!(attr_cap & AURORA_ERR_ATTR_CAP_VALID))
+ goto clear_remaining;
+
+ src = (attr_cap & AURORA_ERR_ATTR_SRC_MSK) >> AURORA_ERR_ATTR_SRC_OFF;
+ if (src <= 3)
+ len += snprintf(msg+len, size-len, "src=CPU%d ", src);
+ else
+ len += snprintf(msg+len, size-len, "src=IO ");
+
+ txn = (attr_cap & AURORA_ERR_ATTR_TXN_MSK) >> AURORA_ERR_ATTR_TXN_OFF;
+ switch (txn) {
+ case 0:
+ len += snprintf(msg+len, size-len, "txn=Data-Read ");
+ break;
+ case 1:
+ len += snprintf(msg+len, size-len, "txn=Isn-Read ");
+ break;
+ case 2:
+ len += snprintf(msg+len, size-len, "txn=Clean-Flush ");
+ break;
+ case 3:
+ len += snprintf(msg+len, size-len, "txn=Eviction ");
+ break;
+ case 4:
+ len += snprintf(msg+len, size-len,
+ "txn=Read-Modify-Write ");
+ break;
+ }
+
+ err = (attr_cap & AURORA_ERR_ATTR_ERR_MSK) >> AURORA_ERR_ATTR_ERR_OFF;
+ switch (err) {
+ case 0:
+ len += snprintf(msg+len, size-len, "err=CorrECC ");
+ break;
+ case 1:
+ len += snprintf(msg+len, size-len, "err=UnCorrECC ");
+ break;
+ case 2:
+ len += snprintf(msg+len, size-len, "err=TagParity ");
+ break;
+ }
+
+ len += snprintf(msg+len, size-len, "addr=0x%x ", addr_cap & AURORA_ERR_ADDR_CAP_ADDR_MASK);
+ len += snprintf(msg+len, size-len, "index=0x%x ", (way_cap & AURORA_ERR_WAY_IDX_MSK) >> AURORA_ERR_WAY_IDX_OFF);
+ len += snprintf(msg+len, size-len, "way=0x%x", (way_cap & AURORA_ERR_WAY_CAP_WAY_MASK) >> AURORA_ERR_WAY_CAP_WAY_OFFSET);
+
+ /* clear error capture registers */
+ writel(AURORA_ERR_ATTR_CAP_VALID, drvdata->base + AURORA_ERR_ATTR_CAP_REG);
+ if (err) {
+ /* UnCorrECC or TagParity */
+ if (cnt_ue)
+ cnt_ue--;
+ edac_device_handle_ue(dci, 0, 0, drvdata->msg);
+ } else {
+ if (cnt_ce)
+ cnt_ce--;
+ edac_device_handle_ce(dci, 0, 0, drvdata->msg);
+ }
+
+clear_remaining:
+ /* report remaining errors */
+ while (cnt_ue--)
+ edac_device_handle_ue(dci, 0, 0, "details unavailable (multiple errors)");
+ while (cnt_ce--)
+ edac_device_handle_ue(dci, 0, 0, "details unavailable (multiple errors)");
+}
+
+static void aurora_l2_poll(struct edac_device_ctl_info *dci)
+{
+#ifdef CONFIG_EDAC_DEBUG
+ struct aurora_l2_drvdata *drvdata = dci->pvt_info;
+#endif
+
+ aurora_l2_check(dci);
+#ifdef CONFIG_EDAC_DEBUG
+ aurora_l2_inject(drvdata);
+#endif
+}
+
+static const struct of_device_id aurora_l2_of_match[] = {
+ {.compatible = "marvell,aurora-system-cache",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, aurora_l2_of_match);
+
+static int aurora_l2_probe(struct platform_device *pdev)
+{
+ struct aurora_l2_drvdata *drvdata;
+ struct edac_device_ctl_info *dci;
+ const struct of_device_id *id;
+ uint32_t l2x0_aux_ctrl;
+ void __iomem *base;
+ struct resource *r;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "Unable to get mem resource\n");
+ return -ENODEV;
+ }
+
+ base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(base)) {
+ dev_err(&pdev->dev, "Unable to map regs\n");
+ return PTR_ERR(base);
+ }
+
+ l2x0_aux_ctrl = readl(base + L2X0_AUX_CTRL);
+ if (!(l2x0_aux_ctrl & AURORA_ACR_PARITY_EN))
+ dev_warn(&pdev->dev, "tag parity is not enabled");
+ if (!(l2x0_aux_ctrl & AURORA_ACR_ECC_EN))
+ dev_warn(&pdev->dev, "data ECC is not enabled");
+
+ dci = edac_device_alloc_ctl_info(sizeof(*drvdata),
+ "cpu", 1, "L", 1, 2, NULL, 0, 0);
+ if (!dci)
+ return -ENOMEM;
+
+ drvdata = dci->pvt_info;
+ drvdata->base = base;
+ dci->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dci);
+
+ id = of_match_device(aurora_l2_of_match, &pdev->dev);
+ dci->edac_check = aurora_l2_poll;
+ dci->mod_name = pdev->dev.driver->name;
+ dci->ctl_name = id ? id->compatible : "unknown";
+ dci->dev_name = dev_name(&pdev->dev);
+
+ /* clear registers */
+ writel(AURORA_ERR_CNT_CLR, drvdata->base + AURORA_ERR_CNT_REG);
+ writel(AURORA_ERR_ATTR_CAP_VALID, drvdata->base + AURORA_ERR_ATTR_CAP_REG);
+
+ if (edac_device_add_device(dci)) {
+ edac_device_free_ctl_info(dci);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_EDAC_DEBUG
+ drvdata->debugfs = edac_debugfs_create_dir(dev_name(&pdev->dev));
+ if (drvdata->debugfs) {
+ edac_debugfs_create_x32("inject_addr", 0644,
+ drvdata->debugfs,
+ &drvdata->inject_addr);
+ edac_debugfs_create_x32("inject_mask", 0644,
+ drvdata->debugfs,
+ &drvdata->inject_mask);
+ edac_debugfs_create_x8("inject_ctl", 0644,
+ drvdata->debugfs, &drvdata->inject_ctl);
+ }
+#endif
+
+ return 0;
+}
+
+static int aurora_l2_remove(struct platform_device *pdev)
+{
+ struct edac_device_ctl_info *dci = platform_get_drvdata(pdev);
+#ifdef CONFIG_EDAC_DEBUG
+ struct aurora_l2_drvdata *drvdata = dci->pvt_info;
+
+ edac_debugfs_remove_recursive(drvdata->debugfs);
+#endif
+ edac_device_del_device(&pdev->dev);
+ edac_device_free_ctl_info(dci);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver aurora_l2_driver = {
+ .probe = aurora_l2_probe,
+ .remove = aurora_l2_remove,
+ .driver = {
+ .name = "aurora_l2_edac",
+ .of_match_table = of_match_ptr(aurora_l2_of_match),
+ },
+};
+
+/************************ Driver registration ******************************/
+
+static struct platform_driver * const drivers[] = {
+ &axp_mc_driver,
+ &aurora_l2_driver,
+};
+
+static int __init armada_xp_edac_init(void)
+{
+ int res;
+
+ /* only polling is supported */
+ edac_op_state = EDAC_OPSTATE_POLL;
+
+ res = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
+ if (res)
+ pr_warn("Aramda XP EDAC drivers fail to register\n");
+
+ return 0;
+}
+module_init(armada_xp_edac_init);
+
+static void __exit armada_xp_edac_exit(void)
+{
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
+}
+module_exit(armada_xp_edac_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Pengutronix");
+MODULE_DESCRIPTION("EDAC Drivers for Marvell Armada XP SDRAM and L2 Cache Controller");
--
2.22.0
^ permalink raw reply related
* [PATCH v9 8/8] EDAC: armada_xp: Add support for more SoCs
From: Chris Packham @ 2019-07-12 3:49 UTC (permalink / raw)
To: bp, robh+dt, mark.rutland, linux, patches, mchehab, james.morse,
jlu
Cc: devicetree, linux-arm-kernel, linux-edac, linux-kernel,
Chris Packham
In-Reply-To: <20190712034904.5747-1-chris.packham@alliedtelesis.co.nz>
The Armada 38x and other integrated SoCs use a reduced pin count so the
width of the SDRAM interface is smaller than the Armada XP SoCs. This
means that the definition of "full" and "half" width is reduced from
64/32 to 32/16.
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
drivers/edac/armada_xp_edac.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/edac/armada_xp_edac.c b/drivers/edac/armada_xp_edac.c
index 3759a4fbbdee..7f227bdcbc84 100644
--- a/drivers/edac/armada_xp_edac.c
+++ b/drivers/edac/armada_xp_edac.c
@@ -332,6 +332,11 @@ static int axp_mc_probe(struct platform_device *pdev)
axp_mc_read_config(mci);
+ /* These SoCs have a reduced width bus */
+ if (of_machine_is_compatible("marvell,armada380") ||
+ of_machine_is_compatible("marvell,armadaxp-98dx3236"))
+ drvdata->width /= 2;
+
/* configure SBE threshold */
/* it seems that SBEs are not captured otherwise */
writel(1 << SDRAM_ERR_CTRL_THR_OFFSET, drvdata->base + SDRAM_ERR_CTRL_REG);
--
2.22.0
^ permalink raw reply related
* Re: [PATCH v8 3/5] mtd: Add support for HyperBus memory devices
From: Vignesh Raghavendra @ 2019-07-12 4:52 UTC (permalink / raw)
To: Sergei Shtylyov, Boris Brezillon, Marek Vasut, Richard Weinberger,
Rob Herring
Cc: devicetree, Tokunori Ikegami, linux-kernel, linux-mtd,
Miquel Raynal, Mason Yang, linux-arm-kernel
In-Reply-To: <e5a7866d-bc34-887d-31d3-de4f745c8d65@cogentembedded.com>
On 12/07/19 12:56 AM, Sergei Shtylyov wrote:
> Hello!
>
> On 06/25/2019 10:57 AM, Vignesh Raghavendra wrote:
>
>> Cypress' HyperBus is Low Signal Count, High Performance Double Data Rate
>> Bus interface between a host system master and one or more slave
>> interfaces. HyperBus is used to connect microprocessor, microcontroller,
>> or ASIC devices with random access NOR flash memory (called HyperFlash)
>> or self refresh DRAM (called HyperRAM).
>>
>> Its a 8-bit data bus (DQ[7:0]) with Read-Write Data Strobe (RWDS)
>> signal and either Single-ended clock(3.0V parts) or Differential clock
>> (1.8V parts). It uses ChipSelect lines to select b/w multiple slaves.
>> At bus level, it follows a separate protocol described in HyperBus
>> specification[1].
>>
>> HyperFlash follows CFI AMD/Fujitsu Extended Command Set (0x0002) similar
>> to that of existing parallel NORs. Since HyperBus is x8 DDR bus,
>> its equivalent to x16 parallel NOR flash with respect to bits per clock
>> cycle. But HyperBus operates at >166MHz frequencies.
>> HyperRAM provides direct random read/write access to flash memory
>> array.
>>
>> But, HyperBus memory controllers seem to abstract implementation details
>> and expose a simple MMIO interface to access connected flash.
>>
>> Add support for registering HyperFlash devices with MTD framework. MTD
>> maps framework along with CFI chip support framework are used to support
>> communicating with flash.
>>
>> Framework is modelled along the lines of spi-nor framework. HyperBus
>> memory controller (HBMC) drivers calls hyperbus_register_device() to
>> register a single HyperFlash device. HyperFlash core parses MMIO access
>> information from DT, sets up the map_info struct, probes CFI flash and
>> registers it with MTD framework.
>>
>> Some HBMC masters need calibration/training sequence[3] to be carried
>> out, in order for DLL inside the controller to lock, by reading a known
>> string/pattern. This is done by repeatedly reading CFI Query
>> Identification String. Calibration needs to be done before trying to detect
>> flash as part of CFI flash probe.
>>
>> HyperRAM is not supported at the moment.
>>
>> HyperBus specification can be found at[1]
>> HyperFlash datasheet can be found at[2]
>>
>> [1] https://www.cypress.com/file/213356/download
>> [2] https://www.cypress.com/file/213346/download
>> [3] http://www.ti.com/lit/ug/spruid7b/spruid7b.pdf
>> Table 12-5741. HyperFlash Access Sequence
>>
>> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
> [...]
>
>> diff --git a/drivers/mtd/hyperbus/hyperbus-core.c b/drivers/mtd/hyperbus/hyperbus-core.c
>> new file mode 100644
>> index 000000000000..63a9e64895bc
>> --- /dev/null
>> +++ b/drivers/mtd/hyperbus/hyperbus-core.c
>> @@ -0,0 +1,154 @@
> [...]
>> +int hyperbus_register_device(struct hyperbus_device *hbdev)
>> +{
> [...]
>> + map->name = dev_name(dev);
>> + map->bankwidth = 2;
>
> I think this should really be 1, judging on the comment to that field (and on
> Cogent's own RPC-IF HF driver).
>
I agree this setting is a bit confusing because DDR nature. What we have
with HyperFlash in DDR mode is equivalent to 16bit flash on a 8bit bus
and kind of equal to 2 bus cycles (in this case clock edges), therefore
bandwidth would turn out to be 2. Otherwise cfi_build_cmd() would
generate wrong addresses and simple map implmention of read/writes would
use wrong accessors.
Only way I see map->bankwidth = 1 working is if HF is used in SDR mode.
So is Cogent's HF in SDR mode? I thought HyperFlash is DDR only but I
may be wrong.
>> + map->device_node = np;
>
> [...]
>
> MBR, Sergei
>
--
Regards
Vignesh
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ 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