* [PATCH v2 05/12] ARM: dts: imx6qdl-apf6dev: Move regulators out of simple-bus
From: Fabio Estevam @ 2017-12-04 12:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512390016-703-1-git-send-email-festevam@gmail.com>
From: Fabio Estevam <fabio.estevam@nxp.com>
It is not recommended to place regulator nodes inside simple-bus, so
move them out in order to fix the following build warnings with W=1:
arch/arm/boot/dts/imx6dl-apf6dev.dtb: Warning (simple_bus_reg): Node /regulators/3p3v missing or empty reg/ranges property
arch/arm/boot/dts/imx6dl-apf6dev.dtb: Warning (simple_bus_reg): Node /regulators/usb-h1-vbus missing or empty reg/ranges property
arch/arm/boot/dts/imx6dl-apf6dev.dtb: Warning (simple_bus_reg): Node /regulators/usb-otg-vbus missing or empty reg/ranges property
Cc: S?bastien Szymanski <sebastien.szymanski@armadeus.com>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
---
Changes since v1:
- None
arch/arm/boot/dts/imx6qdl-apf6dev.dtsi | 44 ++++++++++++++++------------------
1 file changed, 20 insertions(+), 24 deletions(-)
diff --git a/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi b/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
index 829a479..a61dd1a 100644
--- a/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
@@ -111,32 +111,28 @@
};
};
- regulators {
- compatible = "simple-bus";
-
- reg_3p3v: 3p3v {
- compatible = "regulator-fixed";
- regulator-name = "3P3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
- reg_usbh1_vbus: usb-h1-vbus {
- compatible = "regulator-fixed";
- regulator-name = "usb_h1_vbus";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- regulator-always-on;
- };
+ reg_usbh1_vbus: regulator-usb-h1-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_h1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
- reg_usb_otg_vbus: usb-otg-vbus {
- compatible = "regulator-fixed";
- regulator-name = "usb_otg_vbus";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- regulator-always-on;
- };
+ reg_usb_otg_vbus: regulator-usb-otg-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
};
sound {
--
2.7.4
^ permalink raw reply related
* [PATCH v2 04/12] ARM: dts: imx53-tx53-x03x: Move display node out of 'soc'
From: Fabio Estevam @ 2017-12-04 12:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512390016-703-1-git-send-email-festevam@gmail.com>
From: Fabio Estevam <fabio.estevam@nxp.com>
Move disp0 node from soc node to root node.
disp0 node does not have any register properties and thus
shouldn't be placed on the bus.
This fixes the following build warnings with W=1:
arch/arm/boot/dts/imx53-tx53-x03x.dtb: Warning (simple_bus_reg): Node /soc/disp0 missing or empty reg/ranges property
Cc: Lothar Wa?mann <LW@KARO-electronics.de>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
Acked-by: Lothar Wa?mann <LW@KARO-electronics.de>
---
Changes since v1:
- None
arch/arm/boot/dts/imx53-tx53-x03x.dts | 232 +++++++++++++++++-----------------
1 file changed, 115 insertions(+), 117 deletions(-)
diff --git a/arch/arm/boot/dts/imx53-tx53-x03x.dts b/arch/arm/boot/dts/imx53-tx53-x03x.dts
index 7eb53e4..fe15c95 100644
--- a/arch/arm/boot/dts/imx53-tx53-x03x.dts
+++ b/arch/arm/boot/dts/imx53-tx53-x03x.dts
@@ -53,132 +53,130 @@
display = &display;
};
- soc {
- display: disp0 {
- compatible = "fsl,imx-parallel-display";
- interface-pix-fmt = "rgb24";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_rgb24_vga1>;
- status = "okay";
+ display: disp0 {
+ compatible = "fsl,imx-parallel-display";
+ interface-pix-fmt = "rgb24";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgb24_vga1>;
+ status = "okay";
- port {
- display0_in: endpoint {
- remote-endpoint = <&ipu_di0_disp0>;
- };
+ port {
+ display0_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
};
+ };
- display-timings {
- VGA {
- clock-frequency = <25200000>;
- hactive = <640>;
- vactive = <480>;
- hback-porch = <48>;
- hsync-len = <96>;
- hfront-porch = <16>;
- vback-porch = <31>;
- vsync-len = <2>;
- vfront-porch = <12>;
- hsync-active = <0>;
- vsync-active = <0>;
- de-active = <1>;
- pixelclk-active = <0>;
- };
+ display-timings {
+ VGA {
+ clock-frequency = <25200000>;
+ hactive = <640>;
+ vactive = <480>;
+ hback-porch = <48>;
+ hsync-len = <96>;
+ hfront-porch = <16>;
+ vback-porch = <31>;
+ vsync-len = <2>;
+ vfront-porch = <12>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <0>;
+ };
- ETV570 {
- clock-frequency = <25200000>;
- hactive = <640>;
- vactive = <480>;
- hback-porch = <114>;
- hsync-len = <30>;
- hfront-porch = <16>;
- vback-porch = <32>;
- vsync-len = <3>;
- vfront-porch = <10>;
- hsync-active = <0>;
- vsync-active = <0>;
- de-active = <1>;
- pixelclk-active = <0>;
- };
+ ETV570 {
+ clock-frequency = <25200000>;
+ hactive = <640>;
+ vactive = <480>;
+ hback-porch = <114>;
+ hsync-len = <30>;
+ hfront-porch = <16>;
+ vback-porch = <32>;
+ vsync-len = <3>;
+ vfront-porch = <10>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <0>;
+ };
- ET0350 {
- clock-frequency = <6413760>;
- hactive = <320>;
- vactive = <240>;
- hback-porch = <34>;
- hsync-len = <34>;
- hfront-porch = <20>;
- vback-porch = <15>;
- vsync-len = <3>;
- vfront-porch = <4>;
- hsync-active = <0>;
- vsync-active = <0>;
- de-active = <1>;
- pixelclk-active = <0>;
- };
+ ET0350 {
+ clock-frequency = <6413760>;
+ hactive = <320>;
+ vactive = <240>;
+ hback-porch = <34>;
+ hsync-len = <34>;
+ hfront-porch = <20>;
+ vback-porch = <15>;
+ vsync-len = <3>;
+ vfront-porch = <4>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <0>;
+ };
- ET0430 {
- clock-frequency = <9009000>;
- hactive = <480>;
- vactive = <272>;
- hback-porch = <2>;
- hsync-len = <41>;
- hfront-porch = <2>;
- vback-porch = <2>;
- vsync-len = <10>;
- vfront-porch = <2>;
- hsync-active = <0>;
- vsync-active = <0>;
- de-active = <1>;
- pixelclk-active = <1>;
- };
+ ET0430 {
+ clock-frequency = <9009000>;
+ hactive = <480>;
+ vactive = <272>;
+ hback-porch = <2>;
+ hsync-len = <41>;
+ hfront-porch = <2>;
+ vback-porch = <2>;
+ vsync-len = <10>;
+ vfront-porch = <2>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <1>;
+ };
- ET0500 {
- clock-frequency = <33264000>;
- hactive = <800>;
- vactive = <480>;
- hback-porch = <88>;
- hsync-len = <128>;
- hfront-porch = <40>;
- vback-porch = <33>;
- vsync-len = <2>;
- vfront-porch = <10>;
- hsync-active = <0>;
- vsync-active = <0>;
- de-active = <1>;
- pixelclk-active = <0>;
- };
+ ET0500 {
+ clock-frequency = <33264000>;
+ hactive = <800>;
+ vactive = <480>;
+ hback-porch = <88>;
+ hsync-len = <128>;
+ hfront-porch = <40>;
+ vback-porch = <33>;
+ vsync-len = <2>;
+ vfront-porch = <10>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <0>;
+ };
- ET0700 { /* same as ET0500 */
- clock-frequency = <33264000>;
- hactive = <800>;
- vactive = <480>;
- hback-porch = <88>;
- hsync-len = <128>;
- hfront-porch = <40>;
- vback-porch = <33>;
- vsync-len = <2>;
- vfront-porch = <10>;
- hsync-active = <0>;
- vsync-active = <0>;
- de-active = <1>;
- pixelclk-active = <0>;
- };
+ ET0700 { /* same as ET0500 */
+ clock-frequency = <33264000>;
+ hactive = <800>;
+ vactive = <480>;
+ hback-porch = <88>;
+ hsync-len = <128>;
+ hfront-porch = <40>;
+ vback-porch = <33>;
+ vsync-len = <2>;
+ vfront-porch = <10>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <0>;
+ };
- ETQ570 {
- clock-frequency = <6596040>;
- hactive = <320>;
- vactive = <240>;
- hback-porch = <38>;
- hsync-len = <30>;
- hfront-porch = <30>;
- vback-porch = <16>;
- vsync-len = <3>;
- vfront-porch = <4>;
- hsync-active = <0>;
- vsync-active = <0>;
- de-active = <1>;
- pixelclk-active = <0>;
- };
+ ETQ570 {
+ clock-frequency = <6596040>;
+ hactive = <320>;
+ vactive = <240>;
+ hback-porch = <38>;
+ hsync-len = <30>;
+ hfront-porch = <30>;
+ vback-porch = <16>;
+ vsync-len = <3>;
+ vfront-porch = <4>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <0>;
};
};
};
--
2.7.4
^ permalink raw reply related
* [PATCH v2 03/12] ARM: dts: imx53-m53: Remove unneeded reg property
From: Fabio Estevam @ 2017-12-04 12:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512390016-703-1-git-send-email-festevam@gmail.com>
From: Fabio Estevam <fabio.estevam@nxp.com>
As described in
Documentation/devicetree/bindings/input/touchscreen/stmpe.txt
there is no 'reg' property under stmpe_touchscreen, so remove it
to fix the following build warning with W=1:
arch/arm/boot/dts/imx53-m53evk.dtb: Warning (unit_address_vs_reg): Node /soc/aips at 60000000/i2c at 63fc4000/stmpe610 at 41/stmpe_touchscreen has a reg or ranges property, but no unit name
Cc: Marek Vasut <marex@denx.de>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
---
Changes since v1:
- None
arch/arm/boot/dts/imx53-m53.dtsi | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/arm/boot/dts/imx53-m53.dtsi b/arch/arm/boot/dts/imx53-m53.dtsi
index ec390aa5..7ce69c6 100644
--- a/arch/arm/boot/dts/imx53-m53.dtsi
+++ b/arch/arm/boot/dts/imx53-m53.dtsi
@@ -64,7 +64,6 @@
stmpe_touchscreen {
compatible = "st,stmpe-ts";
- reg = <0>;
st,sample-time = <4>;
st,mod-12b = <1>;
st,ref-sel = <0>;
--
2.7.4
^ permalink raw reply related
* [PATCH v2 02/12] ARM: dts: imx51-zii-rdu1: Add the unit addresses in sysled
From: Fabio Estevam @ 2017-12-04 12:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512390016-703-1-git-send-email-festevam@gmail.com>
From: Fabio Estevam <fabio.estevam@nxp.com>
As described at Documentation/devicetree/bindings/mfd/mc13xxx.txt the
reg property is mandatory, so add the corresponding unit address in
order to fix the following build warnings with W=1:
arch/arm/boot/dts/imx51-zii-rdu1.dtb: Warning (unit_address_vs_reg): Node /soc/aips at 70000000/spba at 70000000/ecspi at 70010000/pmic at 0/leds/sysled0 has a reg or ranges property, but no unit name
arch/arm/boot/dts/imx51-zii-rdu1.dtb: Warning (unit_address_vs_reg): Node /soc/aips at 70000000/spba at 70000000/ecspi at 70010000/pmic at 0/leds/sysled1 has a reg or ranges property, but no unit name
Cc: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
---
Changes since v1:
- Removed 'Node /memory has a reg or ranges property, but no unit name' error
arch/arm/boot/dts/imx51-zii-rdu1.dts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/imx51-zii-rdu1.dts b/arch/arm/boot/dts/imx51-zii-rdu1.dts
index f9fdb7c..70fdcdd 100644
--- a/arch/arm/boot/dts/imx51-zii-rdu1.dts
+++ b/arch/arm/boot/dts/imx51-zii-rdu1.dts
@@ -428,13 +428,13 @@
#size-cells = <0>;
led-control = <0x0 0x0 0x3f83f8 0x0>;
- sysled0 {
+ sysled0 at 3 {
reg = <3>;
label = "system:green:status";
linux,default-trigger = "default-on";
};
- sysled1 {
+ sysled1 at 4 {
reg = <4>;
label = "system:green:act";
linux,default-trigger = "heartbeat";
--
2.7.4
^ permalink raw reply related
* [PATCH v2 01/12] ARM: dts: imx51-ts4800: Fix syscon and touschscreen nodes
From: Fabio Estevam @ 2017-12-04 12:20 UTC (permalink / raw)
To: linux-arm-kernel
From: Fabio Estevam <fabio.estevam@nxp.com>
The syscon node has an incorrect notation for its unit address and the
wdt node has an unneeded unit address.
Fix them so that the following build warnings with W=1 are gone:
arch/arm/boot/dts/imx51-ts4800.dtb: Warning (unit_address_vs_reg): Node /soc/aips at 80000000/weim at 83fda000/fpga at 0/syscon at b0010000/wdt at e has a unit name, but no reg property
arch/arm/boot/dts/imx51-ts4800.dtb: Warning (unit_address_vs_reg): Node /soc/aips at 80000000/weim at 83fda000/fpga at 0/touchscreen has a reg or ranges property, but no unit name
arch/arm/boot/dts/imx51-ts4800.dtb: Warning (simple_bus_reg): Node /soc/aips at 80000000/weim at 83fda000/fpga at 0/syscon at b0010000 simple-bus unit address format error, expected "10000"
arch/arm/boot/dts/imx51-ts4800.dtb: Warning (simple_bus_reg): Node /soc/aips at 80000000/weim at 83fda000/fpga at 0/touchscreen simple-bus unit address format error, expected "12000"
Cc: Damien Riegel <damien.riegel@savoirfairelinux.com>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
Reviewed-by: Damien Riegel <damien.riegel@savoirfairelinux.com>
---
Changes since v1:
- Removed 'Node /memory has a reg or ranges property, but no unit name' error
arch/arm/boot/dts/imx51-ts4800.dts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/imx51-ts4800.dts b/arch/arm/boot/dts/imx51-ts4800.dts
index 564233e..f59b02b 100644
--- a/arch/arm/boot/dts/imx51-ts4800.dts
+++ b/arch/arm/boot/dts/imx51-ts4800.dts
@@ -149,18 +149,18 @@
#size-cells = <1>;
ranges = <0 0 0 0x1d000>;
- syscon: syscon at b0010000 {
+ syscon: syscon at 10000 {
compatible = "syscon", "simple-mfd";
reg = <0x10000 0x3d>;
reg-io-width = <2>;
- wdt at e {
+ wdt {
compatible = "technologic,ts4800-wdt";
syscon = <&syscon 0xe>;
};
};
- touchscreen {
+ touchscreen at 12000 {
compatible = "technologic,ts4800-ts";
reg = <0x12000 0x1000>;
syscon = <&syscon 0x10 6>;
--
2.7.4
^ permalink raw reply related
* [PATCH v2 4/5] mm: memory_hotplug: Add memory hotremove probe device
From: Andrea Reale @ 2017-12-04 11:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171130144905.ntpovhy66gekj6e6@dhcp22.suse.cz>
On Thu 30 Nov 2017, 15:49, Michal Hocko wrote:
> On Thu 23-11-17 11:14:52, Andrea Reale wrote:
> > Adding a "remove" sysfs handle that can be used to trigger
> > memory hotremove manually, exactly simmetrically with
> > what happens with the "probe" device for hot-add.
> >
> > This is usueful for architecture that do not rely on
> > ACPI for memory hot-remove.
>
> As already said elsewhere, this really has to check the online status of
> the range and fail some is still online.
>
This is actually still done in remove_memory() (patch 2/5) with
walk_memory_range. We just return an error rather than BUGing().
Or are you referring to something else?
> > Signed-off-by: Andrea Reale <ar@linux.vnet.ibm.com>
> > Signed-off-by: Maciej Bielski <m.bielski@virtualopensystems.com>
> > ---
> > drivers/base/memory.c | 34 +++++++++++++++++++++++++++++++++-
> > 1 file changed, 33 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/base/memory.c b/drivers/base/memory.c
> > index 1d60b58..8ccb67c 100644
> > --- a/drivers/base/memory.c
> > +++ b/drivers/base/memory.c
> > @@ -530,7 +530,36 @@ memory_probe_store(struct device *dev, struct device_attribute *attr,
> > }
> >
> > static DEVICE_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
> > -#endif
> > +
> > +#ifdef CONFIG_MEMORY_HOTREMOVE
> > +static ssize_t
> > +memory_remove_store(struct device *dev,
> > + struct device_attribute *attr, const char *buf, size_t count)
> > +{
> > + u64 phys_addr;
> > + int nid, ret;
> > + unsigned long pages_per_block = PAGES_PER_SECTION * sections_per_block;
> > +
> > + ret = kstrtoull(buf, 0, &phys_addr);
> > + if (ret)
> > + return ret;
> > +
> > + if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
> > + return -EINVAL;
> > +
> > + nid = memory_add_physaddr_to_nid(phys_addr);
> > + ret = lock_device_hotplug_sysfs();
> > + if (ret)
> > + return ret;
> > +
> > + remove_memory(nid, phys_addr,
> > + MIN_MEMORY_BLOCK_SIZE * sections_per_block);
> > + unlock_device_hotplug();
> > + return count;
> > +}
> > +static DEVICE_ATTR(remove, S_IWUSR, NULL, memory_remove_store);
> > +#endif /* CONFIG_MEMORY_HOTREMOVE */
> > +#endif /* CONFIG_ARCH_MEMORY_PROBE */
> >
> > #ifdef CONFIG_MEMORY_FAILURE
> > /*
> > @@ -790,6 +819,9 @@ bool is_memblock_offlined(struct memory_block *mem)
> > static struct attribute *memory_root_attrs[] = {
> > #ifdef CONFIG_ARCH_MEMORY_PROBE
> > &dev_attr_probe.attr,
> > +#ifdef CONFIG_MEMORY_HOTREMOVE
> > + &dev_attr_remove.attr,
> > +#endif
> > #endif
> >
> > #ifdef CONFIG_MEMORY_FAILURE
> > --
> > 2.7.4
Thanks,
Andrea
>
> --
> Michal Hocko
> SUSE Labs
>
^ permalink raw reply
* [PATCH v2 3/5] mm: memory_hotplug: memblock to track partially removed vmemmap mem
From: Andrea Reale @ 2017-12-04 11:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171130145134.el3qq7pr3q4xqglz@dhcp22.suse.cz>
On Thu 30 Nov 2017, 15:51, Michal Hocko wrote:
> On Thu 23-11-17 11:14:38, Andrea Reale wrote:
> > When hot-removing memory we need to free vmemmap memory.
> > However, depending on the memory is being removed, it might
> > not be always possible to free a full vmemmap page / huge-page
> > because part of it might still be used.
> >
> > Commit ae9aae9eda2d ("memory-hotplug: common APIs to support page tables
> > hot-remove") introduced a workaround for x86
> > hot-remove, by which partially unused areas are filled with
> > the 0xFD constant. Full pages are only removed when fully
> > filled by 0xFDs.
> >
> > This commit introduces a MEMBLOCK_UNUSED_VMEMMAP memblock flag, with
> > the goal of using it in place of 0xFDs. For now, this will be used for
> > the arm64 port of memory hot remove, but the idea is to eventually use
> > the same mechanism for x86 as well.
>
> Why cannot you use the same approach as x86 have? Have a look at the
> vmemmap_free at al.
>
This arm64 hot-remove version (including vmemmap_free) is indeed an
almost 1-to-1 port of the x86 approach.
If you look at the first version of the patchset we submitted a while
ago (https://lkml.org/lkml/2017/4/11/540), we were initially using the
x86 approach of filling unsued page structs with 0xFDs. Commenting on
that, Mark suggested (and, indeed, I agree with him) that relying on a
magic constant for marking some portions of physical memory was quite
ugly. That is why we have used memblock for the purpose in this revised
patchset.
If you have a different view and any concrete suggestion on how to
improve this, it is definitely very well welcome.
> > Signed-off-by: Andrea Reale <ar@linux.vnet.ibm.com>
> > Signed-off-by: Maciej Bielski <m.bielski@virtualopensystems.com>
> > ---
> > include/linux/memblock.h | 12 ++++++++++++
> > mm/memblock.c | 32 ++++++++++++++++++++++++++++++++
> > 2 files changed, 44 insertions(+)
> >
> > diff --git a/include/linux/memblock.h b/include/linux/memblock.h
> > index bae11c7..0daec05 100644
> > --- a/include/linux/memblock.h
> > +++ b/include/linux/memblock.h
> > @@ -26,6 +26,9 @@ enum {
> > MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */
> > MEMBLOCK_MIRROR = 0x2, /* mirrored region */
> > MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */
> > +#ifdef CONFIG_MEMORY_HOTREMOVE
> > + MEMBLOCK_UNUSED_VMEMMAP = 0x8, /* Mark VMEMAP blocks as dirty */
> > +#endif
> > };
> >
> > struct memblock_region {
> > @@ -90,6 +93,10 @@ int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
> > int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
> > int memblock_clear_nomap(phys_addr_t base, phys_addr_t size);
> > ulong choose_memblock_flags(void);
> > +#ifdef CONFIG_MEMORY_HOTREMOVE
> > +int memblock_mark_unused_vmemmap(phys_addr_t base, phys_addr_t size);
> > +int memblock_clear_unused_vmemmap(phys_addr_t base, phys_addr_t size);
> > +#endif
> >
> > /* Low level functions */
> > int memblock_add_range(struct memblock_type *type,
> > @@ -182,6 +189,11 @@ static inline bool memblock_is_nomap(struct memblock_region *m)
> > return m->flags & MEMBLOCK_NOMAP;
> > }
> >
> > +#ifdef CONFIG_MEMORY_HOTREMOVE
> > +bool memblock_is_vmemmap_unused_range(struct memblock_type *mt,
> > + phys_addr_t start, phys_addr_t end);
> > +#endif
> > +
> > #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
> > int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
> > unsigned long *end_pfn);
> > diff --git a/mm/memblock.c b/mm/memblock.c
> > index 9120578..30d5aa4 100644
> > --- a/mm/memblock.c
> > +++ b/mm/memblock.c
> > @@ -809,6 +809,18 @@ int __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size)
> > return memblock_setclr_flag(base, size, 0, MEMBLOCK_NOMAP);
> > }
> >
> > +#ifdef CONFIG_MEMORY_HOTREMOVE
> > +int __init_memblock memblock_mark_unused_vmemmap(phys_addr_t base,
> > + phys_addr_t size)
> > +{
> > + return memblock_setclr_flag(base, size, 1, MEMBLOCK_UNUSED_VMEMMAP);
> > +}
> > +int __init_memblock memblock_clear_unused_vmemmap(phys_addr_t base,
> > + phys_addr_t size)
> > +{
> > + return memblock_setclr_flag(base, size, 0, MEMBLOCK_UNUSED_VMEMMAP);
> > +}
> > +#endif
> > /**
> > * __next_reserved_mem_region - next function for for_each_reserved_region()
> > * @idx: pointer to u64 loop variable
> > @@ -1696,6 +1708,26 @@ void __init_memblock memblock_trim_memory(phys_addr_t align)
> > }
> > }
> >
> > +#ifdef CONFIG_MEMORY_HOTREMOVE
> > +bool __init_memblock memblock_is_vmemmap_unused_range(struct memblock_type *mt,
> > + phys_addr_t start, phys_addr_t end)
> > +{
> > + u64 i;
> > + struct memblock_region *r;
> > +
> > + i = memblock_search(mt, start);
> > + r = &(mt->regions[i]);
> > + while (r->base < end) {
> > + if (!(r->flags & MEMBLOCK_UNUSED_VMEMMAP))
> > + return 0;
> > +
> > + r = &(memblock.memory.regions[++i]);
> > + }
> > +
> > + return 1;
> > +}
> > +#endif
> > +
> > void __init_memblock memblock_set_current_limit(phys_addr_t limit)
> > {
> > memblock.current_limit = limit;
> > --
> > 2.7.4
> >
> > --
> > To unsubscribe, send a message with 'unsubscribe linux-mm' in
> > the body to majordomo at kvack.org. For more info on Linux MM,
> > see: http://www.linux-mm.org/ .
> > Don't email: <a href=mailto:"dont@kvack.org"> email at kvack.org </a>
Thanks,
Andrea
>
> --
> Michal Hocko
> SUSE Labs
>
^ permalink raw reply
* [PATCH v2 0/5] Memory hotplug support for arm64 - complete patchset v2
From: Andrea Reale @ 2017-12-04 11:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171130145734.c62ggrx3r7335etc@dhcp22.suse.cz>
Hi Michal,
On Thu 30 Nov 2017, 15:57, Michal Hocko wrote:
> On Thu 23-11-17 17:33:31, Andrea Reale wrote:
> > On Thu 23 Nov 2017, 17:02, Michal Hocko wrote:
> >
> > Hi Michal,
> >
> > > I will try to have a look but I do not expect to understand any of arm64
> > > specific changes so I will focus on the generic code but it would help a
> > > _lot_ if the cover letter provided some overview of what has been done
> > > from a higher level POV. What are the arch pieces and what is the
> > > generic code missing. A quick glance over patches suggests that
> > > changelogs for specific patches are modest as well. Could you give us
> > > more information please? Reviewing hundreds lines of code without
> > > context is a pain.
> >
> > sorry for the lack of details. I will try to provide a better
> > overview in the following. Please, feel free to ask for more details
> > where needed.
> >
> > Overall, the goal of the patchset is to implement arch_memory_add and
> > arch_memory_remove for arm64, to support the generic memory_hotplug
> > framework.
> >
> > Hot add
> > -------
> > Not so many surprises here. We implement the arch specific
> > arch_add_memory, which builds the kernel page tables via hotplug_paging()
> > and then calls arch specific add_pages(). We need the arch specific
> > add_pages() to implement a trick that makes the satus of pages being
> > added accepted by the asumptions made in the generic __add_pages. (See
> > code comments).
>
> Actually I would like to see exactly this explained. The arch support of
> the hotplug should be basically only about arch_add_memory and add_pages
> resp. arch_remove_memory and __remove_pages. Nothing much more, really.
> The core hotplug code should take care of the rest. Ideally you
> shouldn't be really forced to touch the generic code. If yes than this
> should be called out explicitly.
For what concerns hot add, there are no changes to the core hotplug code
whatsoever; just arch_add_memory and add_pages.
For what concerns hot remove, there are two changes to generic code, as
described in the second part of https://lkml.org/lkml/2017/11/23/456.
The first is the removal of the BUG() call in arch_remove_memory and
moving it to ACPI code: I think we agree that calling BUG() from
arch_remove_memory is undesirable. I have to develop a better
understanding on how to get rid of it from ACPI as well.
The second are the memblock changes for vmemmap removal.
I'll try to discuss this change in more details in a follow up email.
Thanks,
Andrea
> --
> Michal Hocko
> SUSE Labs
>
^ permalink raw reply
* [PATCH 11/12] ARM: dts: imx6qdl-nitrogen6_max: Remove unneeded unit address
From: Fabio Estevam @ 2017-12-04 11:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171204113120.wbofrsoxl2ekd3ch@t450s.lan>
Hi Gary,
On Mon, Dec 4, 2017 at 9:31 AM, Gary Bisson
<gary.bisson@boundarydevices.com> wrote:
> Yes exactly, I find it clearer, what do you think?
Yes, I will change it like this.
Thanks
^ permalink raw reply
* [PATCH 11/12] ARM: dts: imx6qdl-nitrogen6_max: Remove unneeded unit address
From: Gary Bisson @ 2017-12-04 11:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOMZO5C77f9mQQWJ5GJH3J+cj4Fxu3H-3yQYeFNDxm3xfpe8Gw@mail.gmail.com>
Hi Fabio,
On Mon, Dec 04, 2017 at 09:28:08AM -0200, Fabio Estevam wrote:
> Hi Gary,
>
> On Mon, Dec 4, 2017 at 9:19 AM, Gary Bisson
> <gary.bisson@boundarydevices.com> wrote:
>
> > What about naming it i2c2mux and i2c3mux so it is clearer those mux
> > happen respectively for i2c2 and i2c3?
> >
> > Then I'd rename the sub-nodes i2cXmux at Y instead of i2cX at Y currently.
> >
> > Let me know your thoughts.
>
> Is this what you suggest?
Yes exactly, I find it clearer, what do you think?
Regards,
Gary
^ permalink raw reply
* [PATCH v2 2/5] mm: memory_hotplug: Remove assumption on memory state before hotremove
From: Andrea Reale @ 2017-12-04 11:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171129015229.GD1469@linux-l9pv.suse>
Hi Joey,
and thanks for your comments. Response inline:
On Wed 29 Nov 2017, 09:52, joeyli wrote:
> On Wed, Nov 29, 2017 at 08:49:13AM +0800, joeyli wrote:
> > Hi Andrea,
> >
> > On Fri, Nov 24, 2017 at 10:22:35AM +0000, Andrea Reale wrote:
> > > Resending the patch adding linux-acpi in CC, as suggested by Rafael.
> > > Everyone else: apologies for the noise.
> > >
> > > Commit 242831eb15a0 ("Memory hotplug / ACPI: Simplify memory removal")
> > > introduced an assumption whereas when control
> > > reaches remove_memory the corresponding memory has been already
> > > offlined. In that case, the acpi_memhotplug was making sure that
> > > the assumption held.
> > > This assumption, however, is not necessarily true if offlining
> > > and removal are not done by the same "controller" (for example,
> > > when first offlining via sysfs).
> > >
> > > Removing this assumption for the generic remove_memory code
> > > and moving it in the specific acpi_memhotplug code. This is
> > > a dependency for the software-aided arm64 offlining and removal
> > > process.
> > >
> > > Signed-off-by: Andrea Reale <ar@linux.vnet.ibm.com>
> > > Signed-off-by: Maciej Bielski <m.bielski@linux.vnet.ibm.com>
> > > ---
> > > drivers/acpi/acpi_memhotplug.c | 2 +-
> > > include/linux/memory_hotplug.h | 9 ++++++---
> > > mm/memory_hotplug.c | 13 +++++++++----
> > > 3 files changed, 16 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
> > > index 6b0d3ef..b0126a0 100644
> > > --- a/drivers/acpi/acpi_memhotplug.c
> > > +++ b/drivers/acpi/acpi_memhotplug.c
> > > @@ -282,7 +282,7 @@ static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
> > > nid = memory_add_physaddr_to_nid(info->start_addr);
> > >
> > > acpi_unbind_memory_blocks(info);
> > > - remove_memory(nid, info->start_addr, info->length);
> > > + BUG_ON(remove_memory(nid, info->start_addr, info->length));
> > > list_del(&info->list);
> > > kfree(info);
> > > }
> > > diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
> > > index 58e110a..1a9c7b2 100644
> > > --- a/include/linux/memory_hotplug.h
> > > +++ b/include/linux/memory_hotplug.h
> > > @@ -295,7 +295,7 @@ static inline bool movable_node_is_enabled(void)
> > > extern bool is_mem_section_removable(unsigned long pfn, unsigned long nr_pages);
> > > extern void try_offline_node(int nid);
> > > extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
> > > -extern void remove_memory(int nid, u64 start, u64 size);
> > > +extern int remove_memory(int nid, u64 start, u64 size);
> > >
> > > #else
> > > static inline bool is_mem_section_removable(unsigned long pfn,
> > > @@ -311,7 +311,10 @@ static inline int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
> > > return -EINVAL;
> > > }
> > >
> > > -static inline void remove_memory(int nid, u64 start, u64 size) {}
> > > +static inline int remove_memory(int nid, u64 start, u64 size)
> > > +{
> > > + return -EINVAL;
> > > +}
> > > #endif /* CONFIG_MEMORY_HOTREMOVE */
> > >
> > > extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
> > > @@ -323,7 +326,7 @@ extern void move_pfn_range_to_zone(struct zone *zone, unsigned long start_pfn,
> > > unsigned long nr_pages);
> > > extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
> > > extern bool is_memblock_offlined(struct memory_block *mem);
> > > -extern void remove_memory(int nid, u64 start, u64 size);
> > > +extern int remove_memory(int nid, u64 start, u64 size);
> > > extern int sparse_add_one_section(struct pglist_data *pgdat, unsigned long start_pfn);
> > > extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms,
> > > unsigned long map_offset);
> > > diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> > > index d4b5f29..d5f15af 100644
> > > --- a/mm/memory_hotplug.c
> > > +++ b/mm/memory_hotplug.c
> > > @@ -1892,7 +1892,7 @@ EXPORT_SYMBOL(try_offline_node);
> > > * and online/offline operations before this call, as required by
> > > * try_offline_node().
> > > */
> > > -void __ref remove_memory(int nid, u64 start, u64 size)
> > > +int __ref remove_memory(int nid, u64 start, u64 size)
> > > {
> > > int ret;
> > >
> > > @@ -1908,18 +1908,23 @@ void __ref remove_memory(int nid, u64 start, u64 size)
> > > ret = walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), NULL,
> > > check_memblock_offlined_cb);
> > > if (ret)
> > > - BUG();
> > > + goto end_remove;
> > > +
> > > + ret = arch_remove_memory(start, size);
>
> Should not include arch_remove_memory() to BUG().
arch_remove_memory might also fail in some cases. In the arm64
implementation of this patchset, for example, it might fail in the
(very rare) case when we would have to split a P[UM]D mapped section for
removal (and we do not support that - see email thread here:
https://lkml.org/lkml/2017/11/23/456).
> > > +
> > > + if (ret)
> > > + goto end_remove;
> >
> > The original code triggers BUG() when any memblock is not offlined. Why
> > the new logic includes the result of arch_remove_memory()?
> >
> > But I agreed the we don't need BUG(). Returning a error is better.
>
> Actually, I lost one thing.
>
> The BUG() have caught a issue about the offline state doesn't sync between
> memory_block and device object. like:
> mem->dev.offline != (mem->state == MEM_OFFLINE)
>
> So, the BUG() is useful to capture state issue in memory subsystem. But, I
> understood your concern about the two steps offline/remove from userland.
>
> Maybe we should move the BUG() to somewhere but not just remove it. Or if
> we think that the BUG() is too intense, at least we should print out a error
> message, and ACPI should checks the return value from subsystem to
> interrupt memory-hotplug process.
In this patchset, BUG() is moved to acpi_memory_remove_memory(),
the caller of arch_remove_memory(). However, I agree with Michal, that
we should not BUG() here but rather halt the hotremove process and print
some errors.
Is there any state in ACPI that should be undone in case of hotremove
errors or we can just stop the process "halfway"?
> Thanks a lot!
> Joey Lee
Thanks,
Andrea
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH 11/12] ARM: dts: imx6qdl-nitrogen6_max: Remove unneeded unit address
From: Fabio Estevam @ 2017-12-04 11:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171204111954.v7jexbtkjyaa6mhe@t450s.lan>
Hi Gary,
On Mon, Dec 4, 2017 at 9:19 AM, Gary Bisson
<gary.bisson@boundarydevices.com> wrote:
> What about naming it i2c2mux and i2c3mux so it is clearer those mux
> happen respectively for i2c2 and i2c3?
>
> Then I'd rename the sub-nodes i2cXmux at Y instead of i2cX at Y currently.
>
> Let me know your thoughts.
Is this what you suggest?
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
@@ -172,7 +172,7 @@
};
};
- i2cmux at 2 {
+ i2c2mux {
compatible = "i2c-mux-gpio";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2mux>;
@@ -183,20 +183,20 @@
i2c-parent = <&i2c2>;
idle-state = <0>;
- i2c2 at 1 {
+ i2c2mux at 1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
};
- i2c2 at 2 {
+ i2c2mux at 2 {
reg = <2>;
#address-cells = <1>;
#size-cells = <0>;
};
};
- i2cmux at 3 {
+ i2c3mux {
compatible = "i2c-mux-gpio";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3mux>;
@@ -206,7 +206,7 @@
i2c-parent = <&i2c3>;
idle-state = <0>;
- i2c3 at 1 {
+ i2c3mux at 1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
^ permalink raw reply
* [PATCH 11/12] ARM: dts: imx6qdl-nitrogen6_max: Remove unneeded unit address
From: Gary Bisson @ 2017-12-04 11:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512156285-18451-11-git-send-email-festevam@gmail.com>
Hi Fabio,
On Fri, Dec 01, 2017 at 05:24:44PM -0200, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@nxp.com>
>
> Remove the unneeded unit address for the i2cmux nodes in order to fix
> the following build warnings with W=1:
>
> arch/arm/boot/dts/imx6q-nitrogen6_max.dtb: Warning (unit_address_vs_reg): Node /i2cmux at 2 has a unit name, but no reg property
> arch/arm/boot/dts/imx6q-nitrogen6_max.dtb: Warning (unit_address_vs_reg): Node /i2cmux at 3 has a unit name, but no reg property
>
> Cc: Gary Bisson <gary.bisson@boundarydevices.com>
> Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
> ---
> arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
> index 3a77f0f..3cdffed 100644
> --- a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
> @@ -172,7 +172,7 @@
> };
> };
>
> - i2cmux at 2 {
> + i2cmux2 {
> compatible = "i2c-mux-gpio";
> pinctrl-names = "default";
> pinctrl-0 = <&pinctrl_i2c2mux>;
> @@ -196,7 +196,7 @@
> };
> };
>
> - i2cmux at 3 {
> + i2cmux3 {
> compatible = "i2c-mux-gpio";
> pinctrl-names = "default";
> pinctrl-0 = <&pinctrl_i2c3mux>;
> --
What about naming it i2c2mux and i2c3mux so it is clearer those mux
happen respectively for i2c2 and i2c3?
Then I'd rename the sub-nodes i2cXmux at Y instead of i2cX at Y currently.
Let me know your thoughts.
Regards,
Gary
^ permalink raw reply
* [PATCH] KVM: arm: Use PTR_ERR_OR_ZERO()
From: Gomonovych, Vasyl @ 2017-12-04 11:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201080049.GB4218@cbox>
Hi Christoffer
It is just syntax sugar of course
and in mentioned function context it looks harmonically because it is
in the end of function return statement.
But in context of around source files it is looks not so harmonically because
existing code uses old approach.
And this old approach is only in one place here.
So it is just a try to fix the warning and may be force to use it in a
future changes.
Regards Vasyl
On Fri, Dec 1, 2017 at 9:00 AM, Christoffer Dall <cdall@linaro.org> wrote:
> Hi Vasyl,
>
> On Tue, Nov 28, 2017 at 11:48:17PM +0100, Vasyl Gomonovych wrote:
>> Fix ptr_ret.cocci warnings:
>> virt/kvm/arm/vgic/vgic-its.c:971:1-3: WARNING: PTR_ERR_OR_ZERO can be used
>>
>> Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR
>>
>> Generated by: scripts/coccinelle/api/ptr_ret.cocci
>
> For new code, sure it would make sense to use this.
>
> But why is it worth changing existing code to use PTR_ERR_OR_ZERO?
>
> Thanks,
> -Christoffer
>
>>
>> Signed-off-by: Vasyl Gomonovych <gomonovych@gmail.com>
>> ---
>> virt/kvm/arm/vgic/vgic-its.c | 4 +---
>> 1 file changed, 1 insertion(+), 3 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
>> index 1f761a9991e7..28d85754320b 100644
>> --- a/virt/kvm/arm/vgic/vgic-its.c
>> +++ b/virt/kvm/arm/vgic/vgic-its.c
>> @@ -1032,10 +1032,8 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
>>
>> device = vgic_its_alloc_device(its, device_id, itt_addr,
>> num_eventid_bits);
>> - if (IS_ERR(device))
>> - return PTR_ERR(device);
>>
>> - return 0;
>> + return PTR_ERR_OR_ZERO(device);
>> }
>>
>> /*
>> --
>> 1.9.1
>>
--
?????? ??? ???? ???.
^ permalink raw reply
* [PATCH 04/12] ARM: dts: imx53-tx53-x03x: Move display node out of 'soc'
From: Lothar Waßmann @ 2017-12-04 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512156285-18451-4-git-send-email-festevam@gmail.com>
Hi,
On Fri, 1 Dec 2017 17:24:37 -0200 Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@nxp.com>
>
> Move disp0 node from soc node to root node.
>
> disp0 node does not have any register properties and thus
> shouldn't be placed on the bus.
>
> This fixes the following build warnings with W=1:
>
> arch/arm/boot/dts/imx53-tx53-x03x.dtb: Warning (simple_bus_reg): Node /soc/disp0 missing or empty reg/ranges property
>
> Cc: Lothar Wa?mann <LW@KARO-electronics.de>
> Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
> ---
> arch/arm/boot/dts/imx53-tx53-x03x.dts | 232 +++++++++++++++++-----------------
> 1 file changed, 115 insertions(+), 117 deletions(-)
>
> diff --git a/arch/arm/boot/dts/imx53-tx53-x03x.dts b/arch/arm/boot/dts/imx53-tx53-x03x.dts
> index 7eb53e4..fe15c95 100644
> --- a/arch/arm/boot/dts/imx53-tx53-x03x.dts
> +++ b/arch/arm/boot/dts/imx53-tx53-x03x.dts
> @@ -53,132 +53,130 @@
> display = &display;
> };
>
> - soc {
> - display: disp0 {
> - compatible = "fsl,imx-parallel-display";
> - interface-pix-fmt = "rgb24";
> - pinctrl-names = "default";
> - pinctrl-0 = <&pinctrl_rgb24_vga1>;
> - status = "okay";
> + display: disp0 {
> + compatible = "fsl,imx-parallel-display";
> + interface-pix-fmt = "rgb24";
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_rgb24_vga1>;
> + status = "okay";
>
> - port {
> - display0_in: endpoint {
> - remote-endpoint = <&ipu_di0_disp0>;
> - };
> + port {
> + display0_in: endpoint {
> + remote-endpoint = <&ipu_di0_disp0>;
> };
> + };
>
> - display-timings {
> - VGA {
> - clock-frequency = <25200000>;
> - hactive = <640>;
> - vactive = <480>;
> - hback-porch = <48>;
> - hsync-len = <96>;
> - hfront-porch = <16>;
> - vback-porch = <31>;
> - vsync-len = <2>;
> - vfront-porch = <12>;
> - hsync-active = <0>;
> - vsync-active = <0>;
> - de-active = <1>;
> - pixelclk-active = <0>;
> - };
> + display-timings {
> + VGA {
> + clock-frequency = <25200000>;
> + hactive = <640>;
> + vactive = <480>;
> + hback-porch = <48>;
> + hsync-len = <96>;
> + hfront-porch = <16>;
> + vback-porch = <31>;
> + vsync-len = <2>;
> + vfront-porch = <12>;
> + hsync-active = <0>;
> + vsync-active = <0>;
> + de-active = <1>;
> + pixelclk-active = <0>;
> + };
>
> - ETV570 {
> - clock-frequency = <25200000>;
> - hactive = <640>;
> - vactive = <480>;
> - hback-porch = <114>;
> - hsync-len = <30>;
> - hfront-porch = <16>;
> - vback-porch = <32>;
> - vsync-len = <3>;
> - vfront-porch = <10>;
> - hsync-active = <0>;
> - vsync-active = <0>;
> - de-active = <1>;
> - pixelclk-active = <0>;
> - };
> + ETV570 {
> + clock-frequency = <25200000>;
> + hactive = <640>;
> + vactive = <480>;
> + hback-porch = <114>;
> + hsync-len = <30>;
> + hfront-porch = <16>;
> + vback-porch = <32>;
> + vsync-len = <3>;
> + vfront-porch = <10>;
> + hsync-active = <0>;
> + vsync-active = <0>;
> + de-active = <1>;
> + pixelclk-active = <0>;
> + };
>
> - ET0350 {
> - clock-frequency = <6413760>;
> - hactive = <320>;
> - vactive = <240>;
> - hback-porch = <34>;
> - hsync-len = <34>;
> - hfront-porch = <20>;
> - vback-porch = <15>;
> - vsync-len = <3>;
> - vfront-porch = <4>;
> - hsync-active = <0>;
> - vsync-active = <0>;
> - de-active = <1>;
> - pixelclk-active = <0>;
> - };
> + ET0350 {
> + clock-frequency = <6413760>;
> + hactive = <320>;
> + vactive = <240>;
> + hback-porch = <34>;
> + hsync-len = <34>;
> + hfront-porch = <20>;
> + vback-porch = <15>;
> + vsync-len = <3>;
> + vfront-porch = <4>;
> + hsync-active = <0>;
> + vsync-active = <0>;
> + de-active = <1>;
> + pixelclk-active = <0>;
> + };
>
> - ET0430 {
> - clock-frequency = <9009000>;
> - hactive = <480>;
> - vactive = <272>;
> - hback-porch = <2>;
> - hsync-len = <41>;
> - hfront-porch = <2>;
> - vback-porch = <2>;
> - vsync-len = <10>;
> - vfront-porch = <2>;
> - hsync-active = <0>;
> - vsync-active = <0>;
> - de-active = <1>;
> - pixelclk-active = <1>;
> - };
> + ET0430 {
> + clock-frequency = <9009000>;
> + hactive = <480>;
> + vactive = <272>;
> + hback-porch = <2>;
> + hsync-len = <41>;
> + hfront-porch = <2>;
> + vback-porch = <2>;
> + vsync-len = <10>;
> + vfront-porch = <2>;
> + hsync-active = <0>;
> + vsync-active = <0>;
> + de-active = <1>;
> + pixelclk-active = <1>;
> + };
>
> - ET0500 {
> - clock-frequency = <33264000>;
> - hactive = <800>;
> - vactive = <480>;
> - hback-porch = <88>;
> - hsync-len = <128>;
> - hfront-porch = <40>;
> - vback-porch = <33>;
> - vsync-len = <2>;
> - vfront-porch = <10>;
> - hsync-active = <0>;
> - vsync-active = <0>;
> - de-active = <1>;
> - pixelclk-active = <0>;
> - };
> + ET0500 {
> + clock-frequency = <33264000>;
> + hactive = <800>;
> + vactive = <480>;
> + hback-porch = <88>;
> + hsync-len = <128>;
> + hfront-porch = <40>;
> + vback-porch = <33>;
> + vsync-len = <2>;
> + vfront-porch = <10>;
> + hsync-active = <0>;
> + vsync-active = <0>;
> + de-active = <1>;
> + pixelclk-active = <0>;
> + };
>
> - ET0700 { /* same as ET0500 */
> - clock-frequency = <33264000>;
> - hactive = <800>;
> - vactive = <480>;
> - hback-porch = <88>;
> - hsync-len = <128>;
> - hfront-porch = <40>;
> - vback-porch = <33>;
> - vsync-len = <2>;
> - vfront-porch = <10>;
> - hsync-active = <0>;
> - vsync-active = <0>;
> - de-active = <1>;
> - pixelclk-active = <0>;
> - };
> + ET0700 { /* same as ET0500 */
> + clock-frequency = <33264000>;
> + hactive = <800>;
> + vactive = <480>;
> + hback-porch = <88>;
> + hsync-len = <128>;
> + hfront-porch = <40>;
> + vback-porch = <33>;
> + vsync-len = <2>;
> + vfront-porch = <10>;
> + hsync-active = <0>;
> + vsync-active = <0>;
> + de-active = <1>;
> + pixelclk-active = <0>;
> + };
>
> - ETQ570 {
> - clock-frequency = <6596040>;
> - hactive = <320>;
> - vactive = <240>;
> - hback-porch = <38>;
> - hsync-len = <30>;
> - hfront-porch = <30>;
> - vback-porch = <16>;
> - vsync-len = <3>;
> - vfront-porch = <4>;
> - hsync-active = <0>;
> - vsync-active = <0>;
> - de-active = <1>;
> - pixelclk-active = <0>;
> - };
> + ETQ570 {
> + clock-frequency = <6596040>;
> + hactive = <320>;
> + vactive = <240>;
> + hback-porch = <38>;
> + hsync-len = <30>;
> + hfront-porch = <30>;
> + vback-porch = <16>;
> + vsync-len = <3>;
> + vfront-porch = <4>;
> + hsync-active = <0>;
> + vsync-active = <0>;
> + de-active = <1>;
> + pixelclk-active = <0>;
> };
> };
> };
Acked-by: Lothar Wa?mann <LW@KARO-electronics.de>
Lothar Wa?mann
^ permalink raw reply
* [PATCH] staging: vc04_services: Fix trivial style issues
From: Dan Carpenter @ 2017-12-04 10:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <30cc7b48def470f1bec8d8d255044f4f220531ee.1512368114.git.sky@genki.is>
On Mon, Dec 04, 2017 at 01:17:36AM -0500, Genki Sky wrote:
> In bcm2835-camera, handle the following checkpatch.pl types:
> - EMBEDDED_FUNCTION_NAME
> - MULTILINE_DEREFERENCE
> - SPLIT_STRING
>
> [ note: this is for Task 10 of http://eudyptula-challenge.org/ ]
Leave this part out or put it under the --- cut off. We don't want it
in the final git log.
>
> Signed-off-by: Genki Sky <sky@genki.is>
Split it up and resend. Then it's a nice little cleanup. It's cool
that checkpatch.pl started complaining about MULTILINE_DEREFERENCEs.
regards,
dan carpenter
^ permalink raw reply
* [PATCH] arm: dts: rockchip: fix errors in IOMMU interrupts property cells
From: Heiko Stuebner @ 2017-12-04 10:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171109223535.17368-1-robh@kernel.org>
Am Donnerstag, 9. November 2017, 16:35:35 CET schrieb Rob Herring:
> The interrupts property in the IOMMU node for Rockchip dts file has a
> spurious extra cell causing a dtc warning:
>
> Warning (interrupts_property): interrupts size is (16), expected multiple of 12 in /iommu at ff900800
>
> Remove the extra cell.
>
> Cc: Heiko Stuebner <heiko@sntech.de>
> Cc: linux-rockchip at lists.infradead.org
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
> arch/arm/boot/dts/rk3288.dtsi | 2 +-
> arch/arm64/boot/dts/rockchip/rk3368.dtsi | 2 +-
Arnd fixed the rk3368 variant in a patch already, so I've dropped that
and applied the rk3288 fix as fix for 4.15.
Thanks
Heiko
^ permalink raw reply
* [PATCH] ARM: dts: rockchip: add cpu0-regulator on rk3066a-marsboard
From: Heiko Stuebner @ 2017-12-04 10:45 UTC (permalink / raw)
To: linux-arm-kernel
The rk3066 also has operating points now, but without adjusting
the cpu-regulator will break once higher voltages are needed for
a specific frequency, so add the needed cpu0-regulator.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
arch/arm/boot/dts/rk3066a-marsboard.dts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/rk3066a-marsboard.dts b/arch/arm/boot/dts/rk3066a-marsboard.dts
index c6d92c25df42..d23ee6d911ac 100644
--- a/arch/arm/boot/dts/rk3066a-marsboard.dts
+++ b/arch/arm/boot/dts/rk3066a-marsboard.dts
@@ -83,6 +83,10 @@
};
};
+&cpu0 {
+ cpu0-supply = <&vdd_arm>;
+};
+
&i2c1 {
status = "okay";
clock-frequency = <400000>;
--
2.14.2
^ permalink raw reply related
* [PATCH] irqchip/gic-v3: Fix the driver probe() fail due to disabled GICC entry
From: Marc Zyngier @ 2017-12-04 10:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512343269-19327-1-git-send-email-shankerd@codeaurora.org>
On 03/12/17 23:21, Shanker Donthineni wrote:
> As per MADT specification, it's perfectly valid firmware can pass
> MADT table to OS with disabled GICC entries. ARM64-SMP code skips
> those cpu cores to bring online. However the current GICv3 driver
> probe bails out in this case on systems where redistributor regions
> are not in the always-on power domain.
>
> This patch does the two things to fix the panic.
> - Don't return an error in gic_acpi_match_gicc() for disabled GICC.
> - No need to keep GICR region information for disabled GICC.
>
> Kernel crash traces:
> Kernel panic - not syncing: No interrupt controller found.
> CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.13.5 #26
> [<ffff000008087770>] dump_backtrace+0x0/0x218
> [<ffff0000080879dc>] show_stack+0x14/0x20
> [<ffff00000883b078>] dump_stack+0x98/0xb8
> [<ffff0000080c5c14>] panic+0x118/0x26c
> [<ffff000008b62348>] init_IRQ+0x24/0x2c
> [<ffff000008b609fc>] start_kernel+0x230/0x394
> [<ffff000008b601e4>] __primary_switched+0x64/0x6c
> ---[ end Kernel panic - not syncing: No interrupt controller found.
>
> Disabled GICC subtable example:
> Subtable Type : 0B [Generic Interrupt Controller]
> Length : 50
> Reserved : 0000
> CPU Interface Number : 0000003D
> Processor UID : 0000003D
> Flags (decoded below) : 00000000
> Processor Enabled : 0
> Performance Interrupt Trig Mode : 0
> Virtual GIC Interrupt Trig Mode : 0
> Parking Protocol Version : 00000000
> Performance Interrupt : 00000017
> Parked Address : 0000000000000000
> Base Address : 0000000000000000
> Virtual GIC Base Address : 0000000000000000
> Hypervisor GIC Base Address : 0000000000000000
> Virtual GIC Interrupt : 00000019
> Redistributor Base Address : 0000FFFF88F40000
> ARM MPIDR : 000000000000000D
> Efficiency Class : 00
> Reserved : 000000
>
> Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org>
> ---
> drivers/irqchip/irq-gic-v3.c | 14 +++++++++-----
> 1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index b56c3e2..a30fbac 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -1331,6 +1331,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
> u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
> void __iomem *redist_base;
>
> + /* GICC entry which has !ACPI_MADT_ENABLED is not unusable so skip */
> + if (!(gicc->flags & ACPI_MADT_ENABLED))
> + return 0;
> +
> redist_base = ioremap(gicc->gicr_base_address, size);
> if (!redist_base)
> return -ENOMEM;
> @@ -1374,13 +1378,13 @@ static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header,
> (struct acpi_madt_generic_interrupt *)header;
>
> /*
> - * If GICC is enabled and has valid gicr base address, then it means
> - * GICR base is presented via GICC
> + * If GICC is enabled and has not valid gicr base address, then it means
> + * GICR base is not presented via GICC
> */
> - if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
> - return 0;
> + if ((gicc->flags & ACPI_MADT_ENABLED) && (!gicc->gicr_base_address))
> + return -ENODEV;
This doesn't feel quite right. It would mean that having the ENABLED
flag cleared and potentially no address would make it valid? It looks to
me that the original code is "less wrong".
What am I missing?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [patch v13 4/4] Documentation: jtag: Add ABI documentation
From: Oleksandr Shamray @ 2017-12-04 10:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512382405-14774-1-git-send-email-oleksandrs@mellanox.com>
Added document that describe the ABI for JTAG class drivrer
Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
v12->v13
v11->v12
Tobias Klauser <tklauser@distanz.ch>
- rename /Documentation/ABI/testing/jatg-dev -> jtag-dev
- Typo: s/interfase/interface
v10->v11
v9->v10
Fixes added by Oleksandr:
- change jtag-cdev to jtag-dev in documentation
- update Kernel Version and Date in jtag-dev documentation;
v8->v9
v7->v8
v6->v7
Comments pointed by Pavel Machek <pavel@ucw.cz>
- Added jtag-cdev documentation to Documentation/ABI/testing folder
---
Documentation/ABI/testing/jtag-dev | 27 +++++++++++++++++++++++++++
1 files changed, 27 insertions(+), 0 deletions(-)
create mode 100644 Documentation/ABI/testing/jtag-dev
diff --git a/Documentation/ABI/testing/jtag-dev b/Documentation/ABI/testing/jtag-dev
new file mode 100644
index 0000000..cab867d
--- /dev/null
+++ b/Documentation/ABI/testing/jtag-dev
@@ -0,0 +1,27 @@
+What: /dev/jtag[0-9]+
+Date: October 2017
+KernelVersion: 4.15
+Contact: oleksandrs at mellanox.com
+Description:
+ The misc device files /dev/jtag* are the interface
+ between JTAG master interface and userspace.
+
+ The ioctl(2)-based ABI is defined and documented in
+ [include/uapi]<linux/jtag.h>.
+
+ The following file operations are supported:
+
+ open(2)
+ The argument flag currently support only one access
+ mode O_RDWR.
+
+ ioctl(2)
+ Initiate various actions.
+ See the inline documentation in [include/uapi]<linux/jtag.h>
+ for descriptions of all ioctls.
+
+ close(2)
+ Stops and free up the I/O contexts that was associated
+ with the file descriptor.
+
+Users: TBD
\ No newline at end of file
--
1.7.1
^ permalink raw reply related
* [patch v13 3/4] Documentation: jtag: Add bindings for Aspeed SoC 24xx and 25xx families JTAG master driver
From: Oleksandr Shamray @ 2017-12-04 10:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512382405-14774-1-git-send-email-oleksandrs@mellanox.com>
It has been tested on Mellanox system with BMC equipped with
Aspeed 2520 SoC for programming CPLD devices.
Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Acked-by: Rob Herring <robh@kernel.org>
---
v12->v13
v11->v12
v10->v11
v9->v10
v8->v9
v7->v8
Comments pointed by pointed by Joel Stanley <joel.stan@gmail.com>
- Change compatible string to ast2400 and ast2000
V6->v7
Comments pointed by Tobias Klauser <tklauser@distanz.ch>
- Fix spell "Doccumentation" -> "Documentation"
v5->v6
Comments pointed by Tobias Klauser <tklauser@distanz.ch>
- Small nit: s/documentation/Documentation/
v4->v5
V3->v4
Comments pointed by Rob Herring <robh@kernel.org>
- delete unnecessary "status" and "reg-shift" descriptions in
bndings file
v2->v3
Comments pointed by Rob Herring <robh@kernel.org>
- split Aspeed jtag driver and binding to sepatrate patches
- delete unnecessary "status" and "reg-shift" descriptions in
bndings file
---
.../devicetree/bindings/jtag/aspeed-jtag.txt | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
diff --git a/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt b/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
new file mode 100644
index 0000000..8cfc610
--- /dev/null
+++ b/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
@@ -0,0 +1,18 @@
+Aspeed JTAG driver for ast2400 and ast2500 SoC
+
+Required properties:
+- compatible: Should be one of
+ - "aspeed,ast2400-jtag"
+ - "aspeed,ast2500-jtag"
+- reg contains the offset and length of the JTAG memory
+ region
+- clocks root clock of bus, should reference the APB clock
+- interrupts should contain JTAG controller interrupt
+
+Example:
+jtag: jtag at 1e6e4000 {
+ compatible = "aspeed,ast2500-jtag";
+ reg = <0x1e6e4000 0x1c>;
+ clocks = <&clk_apb>;
+ interrupts = <43>;
+};
--
1.7.1
^ permalink raw reply related
* [patch v13 2/4] drivers: jtag: Add Aspeed SoC 24xx and 25xx families JTAG master driver
From: Oleksandr Shamray @ 2017-12-04 10:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512382405-14774-1-git-send-email-oleksandrs@mellanox.com>
Driver adds support of Aspeed 2500/2400 series SOC JTAG master controller.
Driver implements the following jtag ops:
- freq_get;
- freq_set;
- status_get;
- idle;
- xfer;
It has been tested on Mellanox system with BMC equipped with
Aspeed 2520 SoC for programming CPLD devices.
Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
v12->v13
Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
- Change jtag-aspeed.c licence type to
SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
and reorder line with license in description
Comments pointed by Kun Yi <kunyi@google.com>
- Changed capability check for aspeed,ast2400-jtag/ast200-jtag
v11->v12
Comments pointed by Chip Bilbrey <chip@bilbrey.org>
- Remove access mode from xfer and idle transactions
- Add new ioctl JTAG_SIOCMODE for set hw mode
v10->v11
v9->v10
V8->v9
Comments pointed by Arnd Bergmann <arnd@arndb.de>
- add *data parameter to xfer function prototype
v7->v8
Comments pointed by Joel Stanley <joel.stan@gmail.com>
- aspeed_jtag_init replace goto to return;
- change input variables type from __u32 to u32
in functios freq_get, freq_set, status_get
- change sm_ variables type from char to u8
- in jatg_init add disable clocks on error case
- remove release_mem_region on error case
- remove devm_free_irq on jtag_deinit
- Fix misspelling Disabe/Disable
- Change compatible string to ast2400 and ast2000
v6->v7
Notifications from kbuild test robot <lkp@intel.com>
- Add include <linux/types.h> to jtag-asapeed.c
v5->v6
v4->v5
Comments pointed by Arnd Bergmann <arnd@arndb.de>
- Added HAS_IOMEM dependence in Kconfig to avoid
"undefined reference to `devm_ioremap_resource'" error,
because in some arch this not supported
v3->v4
Comments pointed by Arnd Bergmann <arnd@arndb.de>
- change transaction pointer tdio type to __u64
- change internal status type from enum to __u32
v2->v3
v1->v2
Comments pointed by Greg KH <gregkh@linuxfoundation.org>
- change license type from GPLv2/BSD to GPLv2
Comments pointed by Neil Armstrong <narmstrong@baylibre.com>
- Add clk_prepare_enable/clk_disable_unprepare in clock init/deinit
- Change .compatible to soc-specific compatible names
aspeed,aspeed4000-jtag/aspeed5000-jtag
- Added dt-bindings
Comments pointed by Arnd Bergmann <arnd@arndb.de>
- Reorder functions and removed the forward declarations
- Add static const qualifier to state machine states transitions
- Change .compatible to soc-specific compatible names
aspeed,aspeed4000-jtag/aspeed5000-jtag
- Add dt-bindings
Comments pointed by Randy Dunlap <rdunlap@infradead.org>
- Change module name jtag-aspeed in description in Kconfig
Comments pointed by kbuild test robot <lkp@intel.com>
- Remove invalid include <asm/mach-types.h>
- add resource_size instead of calculation
---
drivers/jtag/Kconfig | 13 +
drivers/jtag/Makefile | 1 +
drivers/jtag/jtag-aspeed.c | 784 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 798 insertions(+), 0 deletions(-)
create mode 100644 drivers/jtag/jtag-aspeed.c
diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig
index 0fad1a3..098beb0 100644
--- a/drivers/jtag/Kconfig
+++ b/drivers/jtag/Kconfig
@@ -14,3 +14,16 @@ menuconfig JTAG
To compile this driver as a module, choose M here: the module will
be called jtag.
+
+menuconfig JTAG_ASPEED
+ tristate "Aspeed SoC JTAG controller support"
+ depends on JTAG && HAS_IOMEM
+ ---help---
+ This provides a support for Aspeed JTAG device, equipped on
+ Aspeed SoC 24xx and 25xx families. Drivers allows programming
+ of hardware devices, connected to SoC through the JTAG interface.
+
+ If you want this support, you should say Y here.
+
+ To compile this driver as a module, choose M here: the module will
+ be called jtag-aspeed.
diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile
index af37493..04a855e 100644
--- a/drivers/jtag/Makefile
+++ b/drivers/jtag/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_JTAG) += jtag.o
+obj-$(CONFIG_JTAG_ASPEED) += jtag-aspeed.o
diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c
new file mode 100644
index 0000000..2ff46b0
--- /dev/null
+++ b/drivers/jtag/jtag-aspeed.c
@@ -0,0 +1,784 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * drivers/jtag/aspeed-jtag.c
+ *
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Oleksandr Shamray <oleksandrs@mellanox.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/jtag.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <uapi/linux/jtag.h>
+
+#define ASPEED_JTAG_DATA 0x00
+#define ASPEED_JTAG_INST 0x04
+#define ASPEED_JTAG_CTRL 0x08
+#define ASPEED_JTAG_ISR 0x0C
+#define ASPEED_JTAG_SW 0x10
+#define ASPEED_JTAG_TCK 0x14
+#define ASPEED_JTAG_EC 0x18
+
+#define ASPEED_JTAG_DATA_MSB 0x01
+#define ASPEED_JTAG_DATA_CHUNK_SIZE 0x20
+
+/* ASPEED_JTAG_CTRL: Engine Control */
+#define ASPEED_JTAG_CTL_ENG_EN BIT(31)
+#define ASPEED_JTAG_CTL_ENG_OUT_EN BIT(30)
+#define ASPEED_JTAG_CTL_FORCE_TMS BIT(29)
+#define ASPEED_JTAG_CTL_INST_LEN(x) ((x) << 20)
+#define ASPEED_JTAG_CTL_LASPEED_INST BIT(17)
+#define ASPEED_JTAG_CTL_INST_EN BIT(16)
+#define ASPEED_JTAG_CTL_DR_UPDATE BIT(10)
+#define ASPEED_JTAG_CTL_DATA_LEN(x) ((x) << 4)
+#define ASPEED_JTAG_CTL_LASPEED_DATA BIT(1)
+#define ASPEED_JTAG_CTL_DATA_EN BIT(0)
+
+/* ASPEED_JTAG_ISR : Interrupt status and enable */
+#define ASPEED_JTAG_ISR_INST_PAUSE BIT(19)
+#define ASPEED_JTAG_ISR_INST_COMPLETE BIT(18)
+#define ASPEED_JTAG_ISR_DATA_PAUSE BIT(17)
+#define ASPEED_JTAG_ISR_DATA_COMPLETE BIT(16)
+#define ASPEED_JTAG_ISR_INST_PAUSE_EN BIT(3)
+#define ASPEED_JTAG_ISR_INST_COMPLETE_EN BIT(2)
+#define ASPEED_JTAG_ISR_DATA_PAUSE_EN BIT(1)
+#define ASPEED_JTAG_ISR_DATA_COMPLETE_EN BIT(0)
+#define ASPEED_JTAG_ISR_INT_EN_MASK GENMASK(3, 0)
+#define ASPEED_JTAG_ISR_INT_MASK GENMASK(19, 16)
+
+/* ASPEED_JTAG_SW : Software Mode and Status */
+#define ASPEED_JTAG_SW_MODE_EN BIT(19)
+#define ASPEED_JTAG_SW_MODE_TCK BIT(18)
+#define ASPEED_JTAG_SW_MODE_TMS BIT(17)
+#define ASPEED_JTAG_SW_MODE_TDIO BIT(16)
+
+/* ASPEED_JTAG_TCK : TCK Control */
+#define ASPEED_JTAG_TCK_DIVISOR_MASK GENMASK(10, 0)
+#define ASPEED_JTAG_TCK_GET_DIV(x) ((x) & ASPEED_JTAG_TCK_DIVISOR_MASK)
+
+/* ASPEED_JTAG_EC : Controller set for go to IDLE */
+#define ASPEED_JTAG_EC_GO_IDLE BIT(0)
+
+#define ASPEED_JTAG_IOUT_LEN(len) (ASPEED_JTAG_CTL_ENG_EN |\
+ ASPEED_JTAG_CTL_ENG_OUT_EN |\
+ ASPEED_JTAG_CTL_INST_LEN(len))
+
+#define ASPEED_JTAG_DOUT_LEN(len) (ASPEED_JTAG_CTL_ENG_EN |\
+ ASPEED_JTAG_CTL_ENG_OUT_EN |\
+ ASPEED_JTAG_CTL_DATA_LEN(len))
+
+#define ASPEED_JTAG_TCK_WAIT 10
+#define ASPEED_JTAG_RESET_CNTR 10
+
+#define ASPEED_JTAG_NAME "jtag-aspeed"
+
+struct aspeed_jtag {
+ void __iomem *reg_base;
+ struct device *dev;
+ struct clk *pclk;
+ enum jtag_endstate status;
+ int irq;
+ u32 flag;
+ wait_queue_head_t jtag_wq;
+ u32 mode;
+};
+
+static char *end_status_str[] = {"idle", "ir pause", "drpause"};
+
+static u32 aspeed_jtag_read(struct aspeed_jtag *aspeed_jtag, u32 reg)
+{
+ return readl(aspeed_jtag->reg_base + reg);
+}
+
+static void
+aspeed_jtag_write(struct aspeed_jtag *aspeed_jtag, u32 val, u32 reg)
+{
+ writel(val, aspeed_jtag->reg_base + reg);
+}
+
+static int aspeed_jtag_freq_set(struct jtag *jtag, u32 freq)
+{
+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
+ unsigned long apb_frq;
+ u32 tck_val;
+ u16 div;
+
+ apb_frq = clk_get_rate(aspeed_jtag->pclk);
+ div = (apb_frq % freq == 0) ? (apb_frq / freq) - 1 : (apb_frq / freq);
+ tck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);
+ aspeed_jtag_write(aspeed_jtag,
+ (tck_val & ASPEED_JTAG_TCK_DIVISOR_MASK) | div,
+ ASPEED_JTAG_TCK);
+ return 0;
+}
+
+static int aspeed_jtag_freq_get(struct jtag *jtag, u32 *frq)
+{
+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
+ u32 pclk;
+ u32 tck;
+
+ pclk = clk_get_rate(aspeed_jtag->pclk);
+ tck = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);
+ *frq = pclk / (ASPEED_JTAG_TCK_GET_DIV(tck) + 1);
+
+ return 0;
+}
+
+static int aspeed_jtag_mode_set(struct jtag *jtag, u32 mode)
+{
+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
+
+ aspeed_jtag->mode = mode;
+ return 0;
+}
+
+static void aspeed_jtag_sw_delay(struct aspeed_jtag *aspeed_jtag, int cnt)
+{
+ int i;
+
+ for (i = 0; i < cnt; i++)
+ aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW);
+}
+
+static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag,
+ u8 tms, u8 tdi)
+{
+ char tdo = 0;
+
+ /* TCK = 0 */
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
+ (tms * ASPEED_JTAG_SW_MODE_TMS) |
+ (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
+
+ aspeed_jtag_sw_delay(aspeed_jtag, ASPEED_JTAG_TCK_WAIT);
+
+ /* TCK = 1 */
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
+ ASPEED_JTAG_SW_MODE_TCK |
+ (tms * ASPEED_JTAG_SW_MODE_TMS) |
+ (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
+
+ if (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW) &
+ ASPEED_JTAG_SW_MODE_TDIO)
+ tdo = 1;
+
+ aspeed_jtag_sw_delay(aspeed_jtag, ASPEED_JTAG_TCK_WAIT);
+
+ /* TCK = 0 */
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
+ (tms * ASPEED_JTAG_SW_MODE_TMS) |
+ (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
+ return tdo;
+}
+
+static void aspeed_jtag_wait_instruction_pause(struct aspeed_jtag *aspeed_jtag)
+{
+ wait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &
+ ASPEED_JTAG_ISR_INST_PAUSE);
+ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_PAUSE;
+}
+
+static void
+aspeed_jtag_wait_instruction_complete(struct aspeed_jtag *aspeed_jtag)
+{
+ wait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &
+ ASPEED_JTAG_ISR_INST_COMPLETE);
+ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_COMPLETE;
+}
+
+static void
+aspeed_jtag_wait_data_pause_complete(struct aspeed_jtag *aspeed_jtag)
+{
+ wait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &
+ ASPEED_JTAG_ISR_DATA_PAUSE);
+ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_PAUSE;
+}
+
+static void aspeed_jtag_wait_data_complete(struct aspeed_jtag *aspeed_jtag)
+{
+ wait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &
+ ASPEED_JTAG_ISR_DATA_COMPLETE);
+ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_COMPLETE;
+}
+
+static void aspeed_jtag_sm_cycle(struct aspeed_jtag *aspeed_jtag, const u8 *tms,
+ int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ aspeed_jtag_tck_cycle(aspeed_jtag, tms[i], 0);
+}
+
+static void aspeed_jtag_run_test_idle_sw(struct aspeed_jtag *aspeed_jtag,
+ struct jtag_run_test_idle *runtest)
+{
+ static const u8 sm_pause_irpause[] = {1, 1, 1, 1, 0, 1, 0};
+ static const u8 sm_pause_drpause[] = {1, 1, 1, 0, 1, 0};
+ static const u8 sm_idle_irpause[] = {1, 1, 0, 1, 0};
+ static const u8 sm_idle_drpause[] = {1, 0, 1, 0};
+ static const u8 sm_pause_idle[] = {1, 1, 0};
+ int i;
+
+ /* SW mode from idle/pause-> to pause/idle */
+ if (runtest->reset) {
+ for (i = 0; i < ASPEED_JTAG_RESET_CNTR; i++)
+ aspeed_jtag_tck_cycle(aspeed_jtag, 1, 0);
+ }
+
+ switch (aspeed_jtag->status) {
+ case JTAG_STATE_IDLE:
+ switch (runtest->endstate) {
+ case JTAG_STATE_PAUSEIR:
+ /* ->DRSCan->IRSCan->IRCap->IRExit1->PauseIR */
+ aspeed_jtag_sm_cycle(aspeed_jtag, sm_idle_irpause,
+ sizeof(sm_idle_irpause));
+
+ aspeed_jtag->status = JTAG_STATE_PAUSEIR;
+ break;
+ case JTAG_STATE_PAUSEDR:
+ /* ->DRSCan->DRCap->DRExit1->PauseDR */
+ aspeed_jtag_sm_cycle(aspeed_jtag, sm_idle_drpause,
+ sizeof(sm_idle_drpause));
+
+ aspeed_jtag->status = JTAG_STATE_PAUSEDR;
+ break;
+ case JTAG_STATE_IDLE:
+ /* IDLE */
+ aspeed_jtag_tck_cycle(aspeed_jtag, 0, 0);
+ aspeed_jtag->status = JTAG_STATE_IDLE;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case JTAG_STATE_PAUSEIR:
+ /* Fall-through */
+ case JTAG_STATE_PAUSEDR:
+ /* From IR/DR Pause */
+ switch (runtest->endstate) {
+ case JTAG_STATE_PAUSEIR:
+ /*
+ * to Exit2 IR/DR->Updt IR/DR->DRSCan->IRSCan->IRCap->
+ * IRExit1->PauseIR
+ */
+ aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_irpause,
+ sizeof(sm_pause_irpause));
+
+ aspeed_jtag->status = JTAG_STATE_PAUSEIR;
+ break;
+ case JTAG_STATE_PAUSEDR:
+ /*
+ * to Exit2 IR/DR->Updt IR/DR->DRSCan->DRCap->
+ * DRExit1->PauseDR
+ */
+ aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_drpause,
+ sizeof(sm_pause_drpause));
+ aspeed_jtag->status = JTAG_STATE_PAUSEDR;
+ break;
+ case JTAG_STATE_IDLE:
+ /* to Exit2 IR/DR->Updt IR/DR->IDLE */
+ aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_idle,
+ sizeof(sm_pause_idle));
+ aspeed_jtag->status = JTAG_STATE_IDLE;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ dev_err(aspeed_jtag->dev, "aspeed_jtag_run_test_idle error\n");
+ break;
+ }
+
+ /* Stay on IDLE for at least TCK cycle */
+ for (i = 0; i < runtest->tck; i++)
+ aspeed_jtag_tck_cycle(aspeed_jtag, 0, 0);
+}
+
+/**
+ * aspeed_jtag_run_test_idle:
+ * JTAG reset: generates at least 9 TMS high and 1 TMS low to force
+ * devices into Run-Test/Idle State.
+ */
+static int aspeed_jtag_idle(struct jtag *jtag,
+ struct jtag_run_test_idle *runtest)
+{
+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
+
+ dev_dbg(aspeed_jtag->dev, "aspeed_jtag runtest, status:%d, mode:%s, state:%s, reset:%d, tck:%d\n",
+ aspeed_jtag->status,
+ aspeed_jtag->mode & JTAG_XFER_HW_MODE ? "HW" : "SW",
+ end_status_str[runtest->endstate], runtest->reset,
+ runtest->tck);
+
+ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) {
+ aspeed_jtag_run_test_idle_sw(aspeed_jtag, runtest);
+ return 0;
+ }
+
+ /* Disable sw mode */
+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);
+ /* x TMS high + 1 TMS low */
+ if (runtest->reset)
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_CTL_ENG_EN |
+ ASPEED_JTAG_CTL_ENG_OUT_EN |
+ ASPEED_JTAG_CTL_FORCE_TMS, ASPEED_JTAG_CTRL);
+ else
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_EC_GO_IDLE,
+ ASPEED_JTAG_EC);
+
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
+ ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);
+
+ aspeed_jtag->status = JTAG_STATE_IDLE;
+ return 0;
+}
+
+static void aspeed_jtag_xfer_sw(struct aspeed_jtag *aspeed_jtag,
+ struct jtag_xfer *xfer, unsigned long *data)
+{
+ unsigned long remain_xfer = xfer->length;
+ unsigned long shift_bits = 0;
+ unsigned long index = 0;
+ unsigned long tdi;
+ char tdo;
+
+ if (xfer->direction == JTAG_READ_XFER)
+ tdi = UINT_MAX;
+ else
+ tdi = data[index];
+
+ while (remain_xfer > 1) {
+ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0,
+ tdi & ASPEED_JTAG_DATA_MSB);
+ data[index] |= tdo << (shift_bits %
+ ASPEED_JTAG_DATA_CHUNK_SIZE);
+
+ tdi >>= 1;
+ shift_bits++;
+ remain_xfer--;
+
+ if (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE == 0) {
+ dev_dbg(aspeed_jtag->dev, "R/W data[%lu]:%lx\n",
+ index, data[index]);
+
+ tdo = 0;
+ index++;
+
+ if (xfer->direction == JTAG_READ_XFER)
+ tdi = UINT_MAX;
+ else
+ tdi = data[index];
+ }
+ }
+
+ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 1, tdi & ASPEED_JTAG_DATA_MSB);
+ data[index] |= tdo << (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE);
+}
+
+static void aspeed_jtag_xfer_push_data(struct aspeed_jtag *aspeed_jtag,
+ enum jtag_xfer_type type, u32 bits_len)
+{
+ dev_dbg(aspeed_jtag->dev, "shift bits %d\n", bits_len);
+
+ if (type == JTAG_SIR_XFER) {
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_IOUT_LEN(bits_len),
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len) |
+ ASPEED_JTAG_CTL_INST_EN, ASPEED_JTAG_CTRL);
+ } else {
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len),
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len) |
+ ASPEED_JTAG_CTL_DATA_EN, ASPEED_JTAG_CTRL);
+ }
+}
+
+static void aspeed_jtag_xfer_push_data_last(struct aspeed_jtag *aspeed_jtag,
+ enum jtag_xfer_type type,
+ u32 shift_bits,
+ enum jtag_endstate endstate)
+{
+ if (endstate != JTAG_STATE_IDLE) {
+ if (type == JTAG_SIR_XFER) {
+ dev_dbg(aspeed_jtag->dev, "IR Keep Pause\n");
+
+ aspeed_jtag_write(aspeed_jtag,
+ ASPEED_JTAG_IOUT_LEN(shift_bits),
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_write(aspeed_jtag,
+ ASPEED_JTAG_IOUT_LEN(shift_bits) |
+ ASPEED_JTAG_CTL_INST_EN,
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_wait_instruction_pause(aspeed_jtag);
+ } else {
+ dev_dbg(aspeed_jtag->dev, "DR Keep Pause\n");
+ aspeed_jtag_write(aspeed_jtag,
+ ASPEED_JTAG_DOUT_LEN(shift_bits) |
+ ASPEED_JTAG_CTL_DR_UPDATE,
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_write(aspeed_jtag,
+ ASPEED_JTAG_DOUT_LEN(shift_bits) |
+ ASPEED_JTAG_CTL_DR_UPDATE |
+ ASPEED_JTAG_CTL_DATA_EN,
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_wait_data_pause_complete(aspeed_jtag);
+ }
+ } else {
+ if (type == JTAG_SIR_XFER) {
+ dev_dbg(aspeed_jtag->dev, "IR go IDLE\n");
+
+ aspeed_jtag_write(aspeed_jtag,
+ ASPEED_JTAG_IOUT_LEN(shift_bits) |
+ ASPEED_JTAG_CTL_LASPEED_INST,
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_write(aspeed_jtag,
+ ASPEED_JTAG_IOUT_LEN(shift_bits) |
+ ASPEED_JTAG_CTL_LASPEED_INST |
+ ASPEED_JTAG_CTL_INST_EN,
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_wait_instruction_complete(aspeed_jtag);
+ } else {
+ dev_dbg(aspeed_jtag->dev, "DR go IDLE\n");
+
+ aspeed_jtag_write(aspeed_jtag,
+ ASPEED_JTAG_DOUT_LEN(shift_bits) |
+ ASPEED_JTAG_CTL_LASPEED_DATA,
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_write(aspeed_jtag,
+ ASPEED_JTAG_DOUT_LEN(shift_bits) |
+ ASPEED_JTAG_CTL_LASPEED_DATA |
+ ASPEED_JTAG_CTL_DATA_EN,
+ ASPEED_JTAG_CTRL);
+ aspeed_jtag_wait_data_complete(aspeed_jtag);
+ }
+ }
+}
+
+static void aspeed_jtag_xfer_hw(struct aspeed_jtag *aspeed_jtag,
+ struct jtag_xfer *xfer, unsigned long *data)
+{
+ unsigned long remain_xfer = xfer->length;
+ unsigned long index = 0;
+ char shift_bits;
+ u32 data_reg;
+
+ data_reg = xfer->type == JTAG_SIR_XFER ?
+ ASPEED_JTAG_INST : ASPEED_JTAG_DATA;
+ while (remain_xfer) {
+ if (xfer->direction == JTAG_WRITE_XFER) {
+ dev_dbg(aspeed_jtag->dev, "W dr->dr_data[%lu]:%lx\n",
+ index, data[index]);
+
+ aspeed_jtag_write(aspeed_jtag, data[index], data_reg);
+ } else {
+ aspeed_jtag_write(aspeed_jtag, 0, data_reg);
+ }
+
+ if (remain_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) {
+ shift_bits = ASPEED_JTAG_DATA_CHUNK_SIZE;
+
+ /*
+ * Read bytes were not equals to column length
+ * and go to Pause-DR
+ */
+ aspeed_jtag_xfer_push_data(aspeed_jtag, xfer->type,
+ shift_bits);
+ } else {
+ /*
+ * Read bytes equals to column length =>
+ * Update-DR
+ */
+ shift_bits = remain_xfer;
+ aspeed_jtag_xfer_push_data_last(aspeed_jtag, xfer->type,
+ shift_bits,
+ xfer->endstate);
+ }
+
+ if (xfer->direction == JTAG_READ_XFER) {
+ if (shift_bits < ASPEED_JTAG_DATA_CHUNK_SIZE) {
+ data[index] = aspeed_jtag_read(aspeed_jtag,
+ data_reg);
+
+ data[index] >>= ASPEED_JTAG_DATA_CHUNK_SIZE -
+ shift_bits;
+ } else {
+ data[index] = aspeed_jtag_read(aspeed_jtag,
+ data_reg);
+ }
+ dev_dbg(aspeed_jtag->dev, "R dr->dr_data[%lu]:%lx\n",
+ index, data[index]);
+ }
+
+ remain_xfer = remain_xfer - shift_bits;
+ index++;
+ dev_dbg(aspeed_jtag->dev, "remain_xfer %lu\n", remain_xfer);
+ }
+}
+
+static int aspeed_jtag_xfer(struct jtag *jtag, struct jtag_xfer *xfer,
+ u8 *xfer_data)
+{
+ static const u8 sm_update_shiftir[] = {1, 1, 0, 0};
+ static const u8 sm_update_shiftdr[] = {1, 0, 0};
+ static const u8 sm_pause_idle[] = {1, 1, 0};
+ static const u8 sm_pause_update[] = {1, 1};
+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
+ unsigned long *data = (unsigned long *)xfer_data;
+ unsigned long remain_xfer = xfer->length;
+ unsigned long offset;
+ char dbg_str[256];
+ int pos = 0;
+ int i;
+
+ for (offset = 0, i = 0; offset < xfer->length;
+ offset += ASPEED_JTAG_DATA_CHUNK_SIZE, i++) {
+ pos += snprintf(&dbg_str[pos], sizeof(dbg_str) - pos,
+ "0x%08lx ", data[i]);
+ }
+
+ dev_dbg(aspeed_jtag->dev, "aspeed_jtag %s %s xfer, mode:%s, END:%d, len:%lu, TDI[%s]\n",
+ xfer->type == JTAG_SIR_XFER ? "SIR" : "SDR",
+ xfer->direction == JTAG_READ_XFER ? "READ" : "WRITE",
+ aspeed_jtag->mode & JTAG_XFER_HW_MODE ? "HW" : "SW",
+ xfer->endstate, remain_xfer, dbg_str);
+
+ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) {
+ /* SW mode */
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
+ ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);
+
+ if (aspeed_jtag->status != JTAG_STATE_IDLE) {
+ /*IR/DR Pause->Exit2 IR / DR->Update IR /DR */
+ aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_update,
+ sizeof(sm_pause_update));
+ }
+
+ if (xfer->type == JTAG_SIR_XFER)
+ /* ->IRSCan->CapIR->ShiftIR */
+ aspeed_jtag_sm_cycle(aspeed_jtag, sm_update_shiftir,
+ sizeof(sm_update_shiftir));
+ else
+ /* ->DRScan->DRCap->DRShift */
+ aspeed_jtag_sm_cycle(aspeed_jtag, sm_update_shiftdr,
+ sizeof(sm_update_shiftdr));
+
+ aspeed_jtag_xfer_sw(aspeed_jtag, xfer, data);
+
+ /* DIPause/DRPause */
+ aspeed_jtag_tck_cycle(aspeed_jtag, 0, 0);
+
+ if (xfer->endstate == JTAG_STATE_IDLE) {
+ /* ->DRExit2->DRUpdate->IDLE */
+ aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_idle,
+ sizeof(sm_pause_idle));
+ }
+ } else {
+ /* hw mode */
+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);
+ aspeed_jtag_xfer_hw(aspeed_jtag, xfer, data);
+ }
+
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
+ ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);
+ aspeed_jtag->status = xfer->endstate;
+ return 0;
+}
+
+static int aspeed_jtag_status_get(struct jtag *jtag, u32 *status)
+{
+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
+
+ *status = aspeed_jtag->status;
+ return 0;
+}
+
+static irqreturn_t aspeed_jtag_interrupt(s32 this_irq, void *dev_id)
+{
+ struct aspeed_jtag *aspeed_jtag = dev_id;
+ irqreturn_t ret;
+ u32 status;
+
+ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
+ dev_dbg(aspeed_jtag->dev, "status %x\n", status);
+
+ if (status & ASPEED_JTAG_ISR_INT_MASK) {
+ aspeed_jtag_write(aspeed_jtag,
+ (status & ASPEED_JTAG_ISR_INT_MASK)
+ | (status & ASPEED_JTAG_ISR_INT_EN_MASK),
+ ASPEED_JTAG_ISR);
+ aspeed_jtag->flag |= status & ASPEED_JTAG_ISR_INT_MASK;
+ }
+
+ if (aspeed_jtag->flag) {
+ wake_up_interruptible(&aspeed_jtag->jtag_wq);
+ ret = IRQ_HANDLED;
+ } else {
+ dev_err(aspeed_jtag->dev, "aspeed_jtag irq status:%x\n",
+ status);
+ ret = IRQ_NONE;
+ }
+ return ret;
+}
+
+int aspeed_jtag_init(struct platform_device *pdev,
+ struct aspeed_jtag *aspeed_jtag)
+{
+ struct resource *res;
+ int err;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ aspeed_jtag->reg_base = devm_ioremap_resource(aspeed_jtag->dev, res);
+ if (IS_ERR(aspeed_jtag->reg_base))
+ return -ENOMEM;
+
+ aspeed_jtag->pclk = devm_clk_get(aspeed_jtag->dev, NULL);
+ if (IS_ERR(aspeed_jtag->pclk)) {
+ dev_err(aspeed_jtag->dev, "devm_clk_get failed\n");
+ return PTR_ERR(aspeed_jtag->pclk);
+ }
+
+ clk_prepare_enable(aspeed_jtag->pclk);
+
+ aspeed_jtag->irq = platform_get_irq(pdev, 0);
+ if (aspeed_jtag->irq < 0) {
+ dev_err(aspeed_jtag->dev, "no irq specified\n");
+ err = -ENOENT;
+ goto clk_unprep;
+ }
+
+ /* Enable clock */
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_CTL_ENG_EN |
+ ASPEED_JTAG_CTL_ENG_OUT_EN, ASPEED_JTAG_CTRL);
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
+ ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);
+
+ err = devm_request_irq(aspeed_jtag->dev, aspeed_jtag->irq,
+ aspeed_jtag_interrupt, 0,
+ "aspeed-jtag", aspeed_jtag);
+ if (err) {
+ dev_err(aspeed_jtag->dev, "aspeed_jtag unable to get IRQ");
+ goto clk_unprep;
+ }
+ dev_dbg(&pdev->dev, "aspeed_jtag:IRQ %d.\n", aspeed_jtag->irq);
+
+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_INST_PAUSE |
+ ASPEED_JTAG_ISR_INST_COMPLETE |
+ ASPEED_JTAG_ISR_DATA_PAUSE |
+ ASPEED_JTAG_ISR_DATA_COMPLETE |
+ ASPEED_JTAG_ISR_INST_PAUSE_EN |
+ ASPEED_JTAG_ISR_INST_COMPLETE_EN |
+ ASPEED_JTAG_ISR_DATA_PAUSE_EN |
+ ASPEED_JTAG_ISR_DATA_COMPLETE_EN,
+ ASPEED_JTAG_ISR);
+
+ aspeed_jtag->flag = 0;
+ aspeed_jtag->mode = 0;
+ init_waitqueue_head(&aspeed_jtag->jtag_wq);
+ return 0;
+
+clk_unprep:
+ clk_disable_unprepare(aspeed_jtag->pclk);
+ return err;
+}
+
+int aspeed_jtag_deinit(struct platform_device *pdev,
+ struct aspeed_jtag *aspeed_jtag)
+{
+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_ISR);
+ /* Disable clock */
+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL);
+ clk_disable_unprepare(aspeed_jtag->pclk);
+ return 0;
+}
+
+static const struct jtag_ops aspeed_jtag_ops = {
+ .freq_get = aspeed_jtag_freq_get,
+ .freq_set = aspeed_jtag_freq_set,
+ .status_get = aspeed_jtag_status_get,
+ .idle = aspeed_jtag_idle,
+ .xfer = aspeed_jtag_xfer,
+ .mode_set = aspeed_jtag_mode_set
+};
+
+static int aspeed_jtag_probe(struct platform_device *pdev)
+{
+ struct aspeed_jtag *aspeed_jtag;
+ struct device *dev;
+ struct jtag *jtag;
+ int err;
+
+ dev = &pdev->dev;
+ if (!of_device_is_compatible(pdev->dev.of_node,
+ "aspeed,ast2500-jtag") &&
+ !of_device_is_compatible(pdev->dev.of_node,
+ "aspeed,ast2400-jtag"))
+ return -ENODEV;
+
+ jtag = jtag_alloc(sizeof(*aspeed_jtag), &aspeed_jtag_ops);
+ if (!jtag)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, jtag);
+ aspeed_jtag = jtag_priv(jtag);
+ aspeed_jtag->dev = &pdev->dev;
+
+ /* Initialize device*/
+ err = aspeed_jtag_init(pdev, aspeed_jtag);
+ if (err)
+ goto err_jtag_init;
+
+ /* Initialize JTAG core structure*/
+ err = jtag_register(jtag);
+ if (err)
+ goto err_jtag_register;
+
+ return 0;
+
+err_jtag_register:
+ aspeed_jtag_deinit(pdev, aspeed_jtag);
+err_jtag_init:
+ jtag_free(jtag);
+ return err;
+}
+
+static int aspeed_jtag_remove(struct platform_device *pdev)
+{
+ struct jtag *jtag;
+
+ jtag = platform_get_drvdata(pdev);
+ aspeed_jtag_deinit(pdev, jtag_priv(jtag));
+ jtag_unregister(jtag);
+ jtag_free(jtag);
+ return 0;
+}
+
+static const struct of_device_id aspeed_jtag_of_match[] = {
+ { .compatible = "aspeed,ast2400-jtag", },
+ { .compatible = "aspeed,ast2500-jtag", },
+ {}
+};
+
+static struct platform_driver aspeed_jtag_driver = {
+ .probe = aspeed_jtag_probe,
+ .remove = aspeed_jtag_remove,
+ .driver = {
+ .name = ASPEED_JTAG_NAME,
+ .of_match_table = aspeed_jtag_of_match,
+ },
+};
+module_platform_driver(aspeed_jtag_driver);
+
+MODULE_AUTHOR("Oleksandr Shamray <oleksandrs@mellanox.com>");
+MODULE_DESCRIPTION("ASPEED JTAG driver");
+MODULE_LICENSE("GPL v2");
--
1.7.1
^ permalink raw reply related
* [patch v13 1/4] drivers: jtag: Add JTAG core driver
From: Oleksandr Shamray @ 2017-12-04 10:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512382405-14774-1-git-send-email-oleksandrs@mellanox.com>
Initial patch for JTAG driver
JTAG class driver provide infrastructure to support hardware/software
JTAG platform drivers. It provide user layer API interface for flashing
and debugging external devices which equipped with JTAG interface
using standard transactions.
Driver exposes set of IOCTL to user space for:
- XFER:
- SIR (Scan Instruction Register, IEEE 1149.1 Data Register scan);
- SDR (Scan Data Register, IEEE 1149.1 Instruction Register scan);
- RUNTEST (Forces the IEEE 1149.1 bus to a run state for a specified
number of clocks).
- SIOCFREQ/GIOCFREQ for setting and reading JTAG frequency.
Driver core provides set of internal APIs for allocation and
registration:
- jtag_register;
- jtag_unregister;
- jtag_alloc;
- jtag_free;
Platform driver on registration with jtag-core creates the next
entry in dev folder:
/dev/jtagX
Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
v12->v13
Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
- Change jtag.c licence type to
SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
and reorder line with license in description
v11->v12
Comments pointed by Greg KH <gregkh@linuxfoundation.org>
- Change jtag.h licence type to
SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
and reorder line with license in description
Chip Bilbrey <chip@bilbrey.org>
- Remove Apeed reference from uapi jtag.h header
- Remove access mode from xfer and idle transactions
- Add new ioctl JTAG_SIOCMODE for set hw mode
- Add only one open per JTAG port blocking with mutex blocking
v10->v11
Notifications from kbuild test robot <lkp@intel.com>
- include types.h headeri to jtag.h
- fix incompatible type of xfer callback
- remove rdundant class defination
- Fix return order in case of xfer error
V9->v10
Comments pointed by Greg KH <gregkh@linuxfoundation.org>
- remove unnecessary alignment for pirv data
- move jtag_copy_to_user and jtag_copy_from_user code just to ioctl
- move int jtag_run_test_idle_op and jtag_xfer_op code
just to ioctl
- change return error codes to more applicable
- add missing error checks
- fix error check order in ioctl
- remove unnecessary blank lines
- add param validation to ioctl
- remove compat_ioctl
- remove only one open per JTAG port blocking.
User will care about this.
- Fix idr memory leak on jtag_exit
- change cdev device type to misc
V8->v9
Comments pointed by Arnd Bergmann <arnd@arndb.de>
- use get_user() instead of __get_user().
- change jtag->open type from int to atomic_t
- remove spinlock on jtg_open
- remove mutex on jtag_register
- add unregister_chrdev_region on jtag_init err
- add unregister_chrdev_region on jtag_exit
- remove unnecessary pointer casts
- add *data parameter to xfer function prototype
v7->v8
Comments pointed by Moritz Fischer <moritz.fischer@ettus.com>
- Fix misspelling s/friver/driver
v6->v7
Notifications from kbuild test robot <lkp@intel.com>
- Remove include asm/types.h from jtag.h
- Add include <linux/types.h> to jtag.c
v5->v6
v4->v5
v3->v4
Comments pointed by Arnd Bergmann <arnd@arndb.de>
- change transaction pointer tdio type to __u64
- change internal status type from enum to __u32
- reorder jtag_xfer members to avoid the implied padding
- add __packed attribute to jtag_xfer and jtag_run_test_idle
v2->v3
Notifications from kbuild test robot <lkp@intel.com>
- Change include path to <linux/types.h> in jtag.h
v1->v2
Comments pointed by Greg KH <gregkh@linuxfoundation.org>
- Change license type from GPLv2/BSD to GPLv2
- Change type of variables which crossed user/kernel to __type
- Remove "default n" from Kconfig
Comments pointed by Andrew Lunn <andrew@lunn.ch>
- Change list_add_tail in jtag_unregister to list_del
Comments pointed by Neil Armstrong <narmstrong@baylibre.com>
- Add SPDX-License-Identifier instead of license text
Comments pointed by Arnd Bergmann <arnd@arndb.de>
- Change __copy_to_user to memdup_user
- Change __put_user to put_user
- Change type of variables to __type for compatible 32 and 64-bit systems
- Add check for maximum xfer data size
- Change lookup data mechanism to get jtag data from inode
- Add .compat_ioctl to file ops
- Add mem alignment for jtag priv data
Comments pointed by Tobias Klauser <tklauser@distanz.ch>
- Change function names to avoid match with variable types
- Fix description for jtag_ru_test_idle in uapi jtag.h
- Fix misprints IDEL/IDLE, trough/through
---
Documentation/ioctl/ioctl-number.txt | 2 +
MAINTAINERS | 10 ++
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/jtag/Kconfig | 16 ++
drivers/jtag/Makefile | 1 +
drivers/jtag/jtag.c | 289 ++++++++++++++++++++++++++++++++++
include/linux/jtag.h | 46 ++++++
include/uapi/linux/jtag.h | 105 ++++++++++++
9 files changed, 472 insertions(+), 0 deletions(-)
create mode 100644 drivers/jtag/Kconfig
create mode 100644 drivers/jtag/Makefile
create mode 100644 drivers/jtag/jtag.c
create mode 100644 include/linux/jtag.h
create mode 100644 include/uapi/linux/jtag.h
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 3e3fdae..1af2508 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -321,6 +321,8 @@ Code Seq#(hex) Include File Comments
0xB0 all RATIO devices in development:
<mailto:vgo@ratio.de>
0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
+0xB2 00-0f linux/jtag.h JTAG driver
+ <mailto:oleksandrs@mellanox.com>
0xB3 00 linux/mmc/ioctl.h
0xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org>
0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index 205d397..dfcf49c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7292,6 +7292,16 @@ L: linux-serial at vger.kernel.org
S: Maintained
F: drivers/tty/serial/jsm/
+JTAG SUBSYSTEM
+M: Oleksandr Shamray <oleksandrs@mellanox.com>
+M: Vadim Pasternak <vadimp@mellanox.com>
+S: Maintained
+F: include/linux/jtag.h
+F: include/uapi/linux/jtag.h
+F: drivers/jtag/
+F: Documentation/devicetree/bindings/jtag/
+F: Documentation/ABI/testing/jtag-cdev
+
K10TEMP HARDWARE MONITORING DRIVER
M: Clemens Ladisch <clemens@ladisch.de>
L: linux-hwmon at vger.kernel.org
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 505c676..2214678 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -208,4 +208,6 @@ source "drivers/tee/Kconfig"
source "drivers/mux/Kconfig"
+source "drivers/jtag/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index dfdcda0..6a2059b 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -182,3 +182,4 @@ obj-$(CONFIG_FPGA) += fpga/
obj-$(CONFIG_FSI) += fsi/
obj-$(CONFIG_TEE) += tee/
obj-$(CONFIG_MULTIPLEXER) += mux/
+obj-$(CONFIG_JTAG) += jtag/
diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig
new file mode 100644
index 0000000..0fad1a3
--- /dev/null
+++ b/drivers/jtag/Kconfig
@@ -0,0 +1,16 @@
+menuconfig JTAG
+ tristate "JTAG support"
+ ---help---
+ This provides basic core functionality support for jtag class devices
+ Hardware equipped with JTAG microcontroller which can be built
+ on top of this drivers. Driver exposes the set of IOCTL to the
+ user space for:
+ SIR (Scan Instruction Register, IEEE 1149.1 Data Register scan);
+ SDR (Scan Data Register, IEEE 1149.1 Instruction Register scan);
+ RUNTEST (Forces IEEE 1149.1 bus to a run state for specified
+ number of clocks).
+
+ If you want this support, you should say Y here.
+
+ To compile this driver as a module, choose M here: the module will
+ be called jtag.
diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile
new file mode 100644
index 0000000..af37493
--- /dev/null
+++ b/drivers/jtag/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_JTAG) += jtag.o
diff --git a/drivers/jtag/jtag.c b/drivers/jtag/jtag.c
new file mode 100644
index 0000000..42df6e3
--- /dev/null
+++ b/drivers/jtag/jtag.c
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * drivers/jtag/jtag.c
+ *
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Oleksandr Shamray <oleksandrs@mellanox.com>
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/jtag.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/rtnetlink.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <uapi/linux/jtag.h>
+
+#define JTAG_NAME "jtag0"
+#define MAX_JTAG_NAME_LEN (sizeof("jtag") + 5)
+
+struct jtag {
+ struct miscdevice miscdev;
+ struct device *dev;
+ const struct jtag_ops *ops;
+ int id;
+ bool opened;
+ struct mutex open_lock;
+ unsigned long priv[0];
+};
+
+static DEFINE_IDA(jtag_ida);
+
+void *jtag_priv(struct jtag *jtag)
+{
+ return jtag->priv;
+}
+EXPORT_SYMBOL_GPL(jtag_priv);
+
+static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct jtag *jtag = file->private_data;
+ struct jtag_run_test_idle idle;
+ struct jtag_xfer xfer;
+ u8 *xfer_data;
+ u32 data_size;
+ u32 value;
+ int err;
+
+ if (!arg)
+ return -EINVAL;
+
+ switch (cmd) {
+ case JTAG_GIOCFREQ:
+
+ if (jtag->ops->freq_get)
+ err = jtag->ops->freq_get(jtag, &value);
+ else
+ err = -EOPNOTSUPP;
+ if (err)
+ break;
+
+ if (put_user(value, (__u32 *)arg))
+ err = -EFAULT;
+ break;
+
+ case JTAG_SIOCFREQ:
+ if (get_user(value, (__u32 *)arg))
+ return -EFAULT;
+ if (value == 0)
+ return -EINVAL;
+
+ if (jtag->ops->freq_set)
+ err = jtag->ops->freq_set(jtag, value);
+ else
+ err = -EOPNOTSUPP;
+ break;
+
+ case JTAG_IOCRUNTEST:
+ if (copy_from_user(&idle, (void *)arg,
+ sizeof(struct jtag_run_test_idle)))
+ return -EFAULT;
+
+ if (idle.endstate > JTAG_STATE_PAUSEDR)
+ return -EINVAL;
+
+ if (jtag->ops->idle)
+ err = jtag->ops->idle(jtag, &idle);
+ else
+ err = -EOPNOTSUPP;
+ break;
+
+ case JTAG_IOCXFER:
+ if (copy_from_user(&xfer, (void *)arg,
+ sizeof(struct jtag_xfer)))
+ return -EFAULT;
+
+ if (xfer.length >= JTAG_MAX_XFER_DATA_LEN)
+ return -EINVAL;
+
+ if (xfer.type > JTAG_SDR_XFER)
+ return -EINVAL;
+
+ if (xfer.direction > JTAG_WRITE_XFER)
+ return -EINVAL;
+
+ if (xfer.endstate > JTAG_STATE_PAUSEDR)
+ return -EINVAL;
+
+ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE);
+ xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size);
+
+ if (!xfer_data)
+ return -EFAULT;
+
+ if (jtag->ops->xfer) {
+ err = jtag->ops->xfer(jtag, &xfer, xfer_data);
+ } else {
+ kfree(xfer_data);
+ return -EOPNOTSUPP;
+ }
+
+ if (err) {
+ kfree(xfer_data);
+ return -EFAULT;
+ }
+
+ err = copy_to_user(u64_to_user_ptr(xfer.tdio),
+ (void *)(xfer_data), data_size);
+
+ if (err) {
+ kfree(xfer_data);
+ return -EFAULT;
+ }
+
+ kfree(xfer_data);
+ if (copy_to_user((void *)arg, &xfer, sizeof(struct jtag_xfer)))
+ return -EFAULT;
+ break;
+
+ case JTAG_GIOCSTATUS:
+ if (jtag->ops->status_get)
+ err = jtag->ops->status_get(jtag, &value);
+ else
+ err = -EOPNOTSUPP;
+ if (err)
+ break;
+
+ err = put_user(value, (__u32 *)arg);
+ if (err)
+ err = -EFAULT;
+ break;
+ case JTAG_SIOCMODE:
+ if (get_user(value, (__u32 *)arg))
+ return -EFAULT;
+ if (value == 0)
+ return -EINVAL;
+
+ if (jtag->ops->mode_set)
+ err = jtag->ops->mode_set(jtag, value);
+ else
+ err = -EOPNOTSUPP;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return err;
+}
+
+static int jtag_open(struct inode *inode, struct file *file)
+{
+ struct jtag *jtag = container_of(file->private_data, struct jtag,
+ miscdev);
+
+ if (mutex_lock_interruptible(&jtag->open_lock))
+ return -ERESTARTSYS;
+
+ if (jtag->opened) {
+ mutex_unlock(&jtag->open_lock);
+ return -EINVAL;
+ }
+
+ nonseekable_open(inode, file);
+ file->private_data = jtag;
+ jtag->opened = true;
+ mutex_unlock(&jtag->open_lock);
+ return 0;
+}
+
+static int jtag_release(struct inode *inode, struct file *file)
+{
+ struct jtag *jtag = file->private_data;
+
+ mutex_lock(&jtag->open_lock);
+ jtag->opened = false;
+ mutex_unlock(&jtag->open_lock);
+ return 0;
+}
+
+static const struct file_operations jtag_fops = {
+ .owner = THIS_MODULE,
+ .open = jtag_open,
+ .release = jtag_release,
+ .llseek = noop_llseek,
+ .unlocked_ioctl = jtag_ioctl,
+};
+
+struct jtag *jtag_alloc(size_t priv_size, const struct jtag_ops *ops)
+{
+ struct jtag *jtag;
+
+ jtag = kzalloc(sizeof(*jtag) + round_up(priv_size, ARCH_DMA_MINALIGN),
+ GFP_KERNEL);
+ if (!jtag)
+ return NULL;
+
+ jtag->ops = ops;
+ return jtag;
+}
+EXPORT_SYMBOL_GPL(jtag_alloc);
+
+void jtag_free(struct jtag *jtag)
+{
+ kfree(jtag);
+}
+EXPORT_SYMBOL_GPL(jtag_free);
+
+int jtag_register(struct jtag *jtag)
+{
+ char *name;
+ int err;
+ int id;
+
+ id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL);
+ if (id < 0)
+ return id;
+
+ jtag->id = id;
+
+ name = kzalloc(MAX_JTAG_NAME_LEN, GFP_KERNEL);
+ if (!name) {
+ err = -ENOMEM;
+ goto err_jtag_alloc;
+ }
+
+ err = snprintf(name, MAX_JTAG_NAME_LEN, "jtag%d", id);
+ if (err < 0)
+ goto err_jtag_name;
+
+ mutex_init(&jtag->open_lock);
+ jtag->miscdev.fops = &jtag_fops;
+ jtag->miscdev.minor = MISC_DYNAMIC_MINOR;
+ jtag->miscdev.name = name;
+
+ err = misc_register(&jtag->miscdev);
+ if (err)
+ dev_err(jtag->dev, "Unable to register device\n");
+ else
+ return 0;
+ jtag->opened = false;
+
+err_jtag_name:
+ kfree(name);
+err_jtag_alloc:
+ ida_simple_remove(&jtag_ida, id);
+ return err;
+}
+EXPORT_SYMBOL_GPL(jtag_register);
+
+void jtag_unregister(struct jtag *jtag)
+{
+ misc_deregister(&jtag->miscdev);
+ kfree(jtag->miscdev.name);
+ ida_simple_remove(&jtag_ida, jtag->id);
+}
+EXPORT_SYMBOL_GPL(jtag_unregister);
+
+static void __exit jtag_exit(void)
+{
+ ida_destroy(&jtag_ida);
+}
+
+module_exit(jtag_exit);
+
+MODULE_AUTHOR("Oleksandr Shamray <oleksandrs@mellanox.com>");
+MODULE_DESCRIPTION("Generic jtag support");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/jtag.h b/include/linux/jtag.h
new file mode 100644
index 0000000..66b6389
--- /dev/null
+++ b/include/linux/jtag.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * include/linux/jtag.h - JTAG class driver
+ *
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Oleksandr Shamray <oleksandrs@mellanox.com>
+ */
+
+#ifndef __JTAG_H
+#define __JTAG_H
+
+#include <uapi/linux/jtag.h>
+
+#ifndef ARCH_DMA_MINALIGN
+#define ARCH_DMA_MINALIGN 1
+#endif
+
+#define jtag_u64_to_ptr(arg) ((void *)(uintptr_t)arg)
+
+#define JTAG_MAX_XFER_DATA_LEN 65535
+
+struct jtag;
+/**
+ * struct jtag_ops - callbacks for jtag control functions:
+ *
+ * @freq_get: get frequency function. Filled by device driver
+ * @freq_set: set frequency function. Filled by device driver
+ * @status_get: set status function. Filled by device driver
+ * @idle: set JTAG to idle state function. Filled by device driver
+ * @xfer: send JTAG xfer function. Filled by device driver
+ */
+struct jtag_ops {
+ int (*freq_get)(struct jtag *jtag, u32 *freq);
+ int (*freq_set)(struct jtag *jtag, u32 freq);
+ int (*status_get)(struct jtag *jtag, u32 *state);
+ int (*idle)(struct jtag *jtag, struct jtag_run_test_idle *idle);
+ int (*xfer)(struct jtag *jtag, struct jtag_xfer *xfer, u8 *xfer_data);
+ int (*mode_set)(struct jtag *jtag, u32 mode_mask);
+};
+
+void *jtag_priv(struct jtag *jtag);
+int jtag_register(struct jtag *jtag);
+void jtag_unregister(struct jtag *jtag);
+struct jtag *jtag_alloc(size_t priv_size, const struct jtag_ops *ops);
+void jtag_free(struct jtag *jtag);
+
+#endif /* __JTAG_H */
diff --git a/include/uapi/linux/jtag.h b/include/uapi/linux/jtag.h
new file mode 100644
index 0000000..b6c4dde
--- /dev/null
+++ b/include/uapi/linux/jtag.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ * include/uapi/linux/jtag.h - JTAG class driver uapi
+ *
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Oleksandr Shamray <oleksandrs@mellanox.com>
+ */
+
+#ifndef __UAPI_LINUX_JTAG_H
+#define __UAPI_LINUX_JTAG_H
+
+#include <linux/types.h>
+/*
+ * JTAG_XFER_HW_MODE: JTAG hardware mode. Used to set HW drived or bitbang
+ * mode. This is bitmask param of ioctl JTAG_SIOCMODE command
+ */
+#define JTAG_XFER_HW_MODE 1
+
+/**
+ * enum jtag_endstate:
+ *
+ * @JTAG_STATE_IDLE: JTAG state machine IDLE state
+ * @JTAG_STATE_PAUSEIR: JTAG state machine PAUSE_IR state
+ * @JTAG_STATE_PAUSEDR: JTAG state machine PAUSE_DR state
+ */
+enum jtag_endstate {
+ JTAG_STATE_IDLE,
+ JTAG_STATE_PAUSEIR,
+ JTAG_STATE_PAUSEDR,
+};
+
+/**
+ * enum jtag_xfer_type:
+ *
+ * @JTAG_SIR_XFER: SIR transfer
+ * @JTAG_SDR_XFER: SDR transfer
+ */
+enum jtag_xfer_type {
+ JTAG_SIR_XFER,
+ JTAG_SDR_XFER,
+};
+
+/**
+ * enum jtag_xfer_direction:
+ *
+ * @JTAG_READ_XFER: read transfer
+ * @JTAG_WRITE_XFER: write transfer
+ */
+enum jtag_xfer_direction {
+ JTAG_READ_XFER,
+ JTAG_WRITE_XFER,
+};
+
+/**
+ * struct jtag_run_test_idle - forces JTAG state machine to
+ * RUN_TEST/IDLE state
+ *
+ * @reset: 0 - run IDLE/PAUSE from current state
+ * 1 - go through TEST_LOGIC/RESET state before IDLE/PAUSE
+ * @end: completion flag
+ * @tck: clock counter
+ *
+ * Structure represents interface to JTAG device for jtag idle
+ * execution.
+ */
+struct jtag_run_test_idle {
+ __u8 reset;
+ __u8 endstate;
+ __u8 tck;
+};
+
+/**
+ * struct jtag_xfer - jtag xfer:
+ *
+ * @type: transfer type
+ * @direction: xfer direction
+ * @length: xfer bits len
+ * @tdio : xfer data array
+ * @endir: xfer end state
+ *
+ * Structure represents interface to JTAG device for jtag sdr xfer
+ * execution.
+ */
+struct jtag_xfer {
+ __u8 type;
+ __u8 direction;
+ __u8 endstate;
+ __u32 length;
+ __u64 tdio;
+};
+
+/* ioctl interface */
+#define __JTAG_IOCTL_MAGIC 0xb2
+
+#define JTAG_IOCRUNTEST _IOW(__JTAG_IOCTL_MAGIC, 0,\
+ struct jtag_run_test_idle)
+#define JTAG_SIOCFREQ _IOW(__JTAG_IOCTL_MAGIC, 1, unsigned int)
+#define JTAG_GIOCFREQ _IOR(__JTAG_IOCTL_MAGIC, 2, unsigned int)
+#define JTAG_IOCXFER _IOWR(__JTAG_IOCTL_MAGIC, 3, struct jtag_xfer)
+#define JTAG_GIOCSTATUS _IOWR(__JTAG_IOCTL_MAGIC, 4, enum jtag_endstate)
+#define JTAG_SIOCMODE _IOW(__JTAG_IOCTL_MAGIC, 5, unsigned int)
+
+#define JTAG_FIRST_MINOR 0
+#define JTAG_MAX_DEVICES 32
+
+#endif /* __UAPI_LINUX_JTAG_H */
--
1.7.1
^ permalink raw reply related
* [patch v13 0/4] JTAG driver introduction
From: Oleksandr Shamray @ 2017-12-04 10:13 UTC (permalink / raw)
To: linux-arm-kernel
When a need raise up to use JTAG interface for system's devices
programming or CPU debugging, usually the user layer
application implements jtag protocol by bit-bang or using a
proprietary connection to vendor hardware.
This method can be slow and not generic.
We propose to implement general JTAG interface and infrastructure
to communicate with user layer application. In such way, we can
have the standard JTAG interface core part and separation from
specific HW implementation.
This allow new capability to debug the CPU or program system's
device via BMC without additional devices nor cost.
This patch purpose is to add JTAG master core infrastructure by
defining new JTAG class and provide generic JTAG interface
to allow hardware specific drivers to connect this interface.
This will enable all JTAG drivers to use the common interface
part and will have separate for hardware implementation.
The JTAG (Joint Test Action Group) core driver provides minimal generic
JTAG interface, which can be used by hardware specific JTAG master
controllers. By providing common interface for the JTAG controllers,
user space device programing is hardware independent.
Modern SoC which in use for embedded system' equipped with
internal JTAG master interface.
This interface is used for programming and debugging system's
hardware components, like CPLD, FPGA, CPU, voltage and
industrial controllers.
Firmware for such devices can be upgraded through JTAG interface during
Runtime. The JTAG standard support for multiple devices programming,
is in case their lines are daisy-chained together.
For example, systems which equipped with host CPU, BMC SoC or/and
number of programmable devices are capable to connect a pin and
select system components dynamically for programming and debugging,
This is using by the BMC which is equipped with internal SoC master
controller.
For example:
BMC JTAG master --> pin selected to CPLDs chain for programming (filed
upgrade, production)
BMC JTAG master --> pin selected to voltage monitors for programming
(field upgrade, production)
BMC JTAG master --> pin selected to host CPU (on-site debugging
and developers debugging)
For example, we can have application in user space which using calls
to JTAG driver executes CPLD programming directly from SVF file
The JTAG standard (IEEE 1149.1) defines the next connector pins:
- TDI (Test Data In);
- TDO (Test Data Out);
- TCK (Test Clock);
- TMS (Test Mode Select);
- TRST (Test Reset) (Optional);
The SoC equipped with JTAG master controller, performs
device programming on command or vector level. For example
a file in a standard SVF (Serial Vector Format) that contains
boundary scan vectors, can be used by sending each vector
to the JTAG interface and the JTAG controller will execute
the programming.
Initial version provides the system calls set for:
- SIR (Scan Instruction Register, IEEE 1149.1 Data Register scan);
- SDR (Scan Data Register, IEEE 1149.1 Instruction Register scan);
- RUNTEST (Forces the IEEE 1149.1 bus to a run state for a specified
number of clocks.
SoC which are not equipped with JTAG master interface, can be built
on top of JTAG core driver infrastructure, by applying bit-banging of
TDI, TDO, TCK and TMS pins within the hardware specific driver.
Oleksandr Shamray (4):
drivers: jtag: Add JTAG core driver
drivers: jtag: Add Aspeed SoC 24xx and 25xx families JTAG master
driver
Documentation: jtag: Add bindings for Aspeed SoC 24xx and 25xx
families JTAG master driver
Documentation: jtag: Add ABI documentation
Documentation/ABI/testing/jtag-dev | 27 +
.../devicetree/bindings/jtag/aspeed-jtag.txt | 18 +
Documentation/ioctl/ioctl-number.txt | 2 +
MAINTAINERS | 10 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/jtag/Kconfig | 29 +
drivers/jtag/Makefile | 2 +
drivers/jtag/jtag-aspeed.c | 784 ++++++++++++++++++++
drivers/jtag/jtag.c | 289 +++++++
include/linux/jtag.h | 46 ++
include/uapi/linux/jtag.h | 105 +++
12 files changed, 1315 insertions(+), 0 deletions(-)
create mode 100644 Documentation/ABI/testing/jtag-dev
create mode 100644 Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
create mode 100644 drivers/jtag/Kconfig
create mode 100644 drivers/jtag/Makefile
create mode 100644 drivers/jtag/jtag-aspeed.c
create mode 100644 drivers/jtag/jtag.c
create mode 100644 include/linux/jtag.h
create mode 100644 include/uapi/linux/jtag.h
^ permalink raw reply
* [PATCH] KVM: arm/arm64: Fix broken GICH_ELRSR big endian conversion
From: Marc Zyngier @ 2017-12-04 10:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203230435.22021-1-cdall@kernel.org>
On 03/12/17 23:04, Christoffer Dall wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
>
> We are incorrectly rearranging 32-bit words inside a 64-bit typed value
> for big endian systems, which would result in never marking a virtual
> interrupt as inactive on big endian systems (assuming 32 or fewer LRs on
> the hardware). Fix this by not doing any word order manipulation for
> the typed values.
>
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> virt/kvm/arm/hyp/vgic-v2-sr.c | 4 ----
> 1 file changed, 4 deletions(-)
>
> diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
> index a3f18d362366..d7fd46fe9efb 100644
> --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
> @@ -34,11 +34,7 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
> else
> elrsr1 = 0;
>
> -#ifdef CONFIG_CPU_BIG_ENDIAN
> - cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
> -#else
> cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
> -#endif
> }
>
> static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
>
Duh!
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
M.
--
Jazz is not dead. It just smells funny...
^ 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