* [PATCH 2/2] arm64: dts: exynos: Remove unneeded DSI and DECON address/size cells in Exynos5433
From: Andrzej Hajda @ 2018-06-21 5:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180620193407.gk5e5ecolo5bel3c@kozik-lap>
On 20.06.2018 21:34, Krzysztof Kozlowski wrote:
> On Tue, Jun 19, 2018 at 09:59:04AM +0200, Krzysztof Kozlowski wrote:
>> On 19 June 2018 at 09:26, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>>> Hi Krzysztof,
>>>
>>> On 2018-06-18 19:42, Krzysztof Kozlowski wrote:
>>>> The decon, decon_tv and dsi nodes have only one child port so
>>>> address/size mappings are not necessary. This fixes DTC warnings like:
>>>>
>>>> Warning (graph_child_address): /soc/decon at 13800000/ports:
>>>> graph node has single child node 'port at 0', #address-cells/#size-cells are not necessary
>>>>
>>>> Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
>>> Works fine with current Exynos DRM Decon/MIC/DSI drivers.
>>>
>>> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> Thanks for review and testing!
> I have second thoughs whether this patch is correct. AFAIU, the drivers
> get the remote endpoints by reg==0 (for example the
> of_graph_get_remote_node() in exynos_dsi_parse_dt()). If the port shall
> be ignored, then reg==-1 should be passed.
All this is about purity, DECON bindings says explicitly that there
should be a port with reg=0.
So your patch and DTC warnings are incorrect from bindings PoV.
On the other side graph bindings are too bloated ( so many lines to
describe one connection ) so I am happy if there are shrinking attempts :)
Functionally nothing changes, of graph helpers assume reg=0 if it is not
present in port/endpoint node.
And regarding real issues, DECON could have more ports, possible candidates:
- GSCALER0/1/2,
- GSD/DSD - interconnect between GSCALERs and DECONs,
- SMIES - image enhancer (not implemented),
- MIC0/1 - image enhancers,
- DSIM0/1 - DSI encoders,
- HDMI - HDMI encoder.
But since all these connections can be configured dynamically, and more
importantly are inside specific SoC I dont think they need of_graphs. In
fact I think current of graph is also not necessary, but this is
different story, removal is on my long TODO list :)
Regards
Andrzej
>
> Best regards,
> Krzysztof
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" 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 v4] dt-bindings: mediatek: Add binding for mt2712 IOMMU and SMI
From: Yong Wu @ 2018-06-21 6:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527165331-22261-1-git-send-email-yong.wu@mediatek.com>
Hi Matthias,
A gentle ping on this.
On Thu, 2018-05-24 at 20:35 +0800, Yong Wu wrote:
> This patch adds decriptions for mt2712 IOMMU and SMI.
>
> In order to balance the bandwidth, mt2712 has two M4Us, two
> smi-commons, 10 smi-larbs. and mt2712 is also MTK IOMMU gen2 which
> uses ARM Short-Descriptor translation table format.
>
> The mt2712 M4U-SMI HW diagram is as below:
>
> EMI
> |
> ------------------------------------
> | |
> M4U0 M4U1
> | |
> smi-common0 smi-common1
> | |
> ------------------------- --------------------------------
> | | | | | | | | | |
> | | | | | | | | | |
> larb0 larb1 larb2 larb3 larb6 larb4 larb5 larb7 larb8 larb9
> disp0 vdec cam venc jpg mdp1/disp1 mdp2/disp2 mdp3 vdo/nr tvd
>
> All the connections are HW fixed, SW can NOT adjust it.
>
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> Acked-by: Rob Herring <robh@kernel.org>
> ---
> change notes:
> v4: change the license of the new file in this patch to SPDX.
>
> v3: http://lists.infradead.org/pipermail/linux-mediatek/2018-May/013279.html
> Add a new ECO port(DISP_RDMA2) in larb0/port7.
>
> v2:
> https://lists.linuxfoundation.org/pipermail/iommu/2017-August/023848.html
>
> v1:
> https://lists.linuxfoundation.org/pipermail/iommu/2017-August/023665.html
> ---
> .../devicetree/bindings/iommu/mediatek,iommu.txt | 6 +-
> .../memory-controllers/mediatek,smi-common.txt | 6 +-
> .../memory-controllers/mediatek,smi-larb.txt | 5 +-
> include/dt-bindings/memory/mt2712-larb-port.h | 95 ++++++++++++++++++++++
> 4 files changed, 106 insertions(+), 6 deletions(-)
> create mode 100644 include/dt-bindings/memory/mt2712-larb-port.h
>
> diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> index 53c20ca..df5db73 100644
> --- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> +++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> @@ -40,6 +40,7 @@ video decode local arbiter, all these ports are according to the video HW.
> Required properties:
> - compatible : must be one of the following string:
> "mediatek,mt2701-m4u" for mt2701 which uses generation one m4u HW.
> + "mediatek,mt2712-m4u" for mt2712 which uses generation two m4u HW.
> "mediatek,mt8173-m4u" for mt8173 which uses generation two m4u HW.
> - reg : m4u register base and size.
> - interrupts : the interrupt of m4u.
> @@ -50,8 +51,9 @@ Required properties:
> according to the local arbiter index, like larb0, larb1, larb2...
> - iommu-cells : must be 1. This is the mtk_m4u_id according to the HW.
> Specifies the mtk_m4u_id as defined in
> - dt-binding/memory/mt2701-larb-port.h for mt2701 and
> - dt-binding/memory/mt8173-larb-port.h for mt8173
> + dt-binding/memory/mt2701-larb-port.h for mt2701,
> + dt-binding/memory/mt2712-larb-port.h for mt2712, and
> + dt-binding/memory/mt8173-larb-port.h for mt8173.
>
> Example:
> iommu: iommu at 10205000 {
> diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
> index aa614b2..615abdd 100644
> --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
> +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
> @@ -2,8 +2,9 @@ SMI (Smart Multimedia Interface) Common
>
> The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
>
> -Mediatek SMI have two generations of HW architecture, mt8173 uses the second
> -generation of SMI HW while mt2701 uses the first generation HW of SMI.
> +Mediatek SMI have two generations of HW architecture, mt2712 and mt8173 use
> +the second generation of SMI HW while mt2701 uses the first generation HW of
> +SMI.
>
> There's slight differences between the two SMI, for generation 2, the
> register which control the iommu port is at each larb's register base. But
> @@ -15,6 +16,7 @@ not needed for SMI generation 2.
> Required properties:
> - compatible : must be one of :
> "mediatek,mt2701-smi-common"
> + "mediatek,mt2712-smi-common"
> "mediatek,mt8173-smi-common"
> - reg : the register and size of the SMI block.
> - power-domains : a phandle to the power domain of this local arbiter.
> diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
> index ddf46b8..083155c 100644
> --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
> +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
> @@ -4,8 +4,9 @@ The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
>
> Required properties:
> - compatible : must be one of :
> - "mediatek,mt8173-smi-larb"
> "mediatek,mt2701-smi-larb"
> + "mediatek,mt2712-smi-larb"
> + "mediatek,mt8173-smi-larb"
> - reg : the register and size of this local arbiter.
> - mediatek,smi : a phandle to the smi_common node.
> - power-domains : a phandle to the power domain of this local arbiter.
> @@ -15,7 +16,7 @@ Required properties:
> the register.
> - "smi" : It's the clock for transfer data and command.
>
> -Required property for mt2701:
> +Required property for mt2701 and mt2712:
> - mediatek,larb-id :the hardware id of this larb.
>
> Example:
> diff --git a/include/dt-bindings/memory/mt2712-larb-port.h b/include/dt-bindings/memory/mt2712-larb-port.h
> new file mode 100644
> index 0000000..6f9aa73
> --- /dev/null
> +++ b/include/dt-bindings/memory/mt2712-larb-port.h
> @@ -0,0 +1,95 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2017 MediaTek Inc.
> + * Author: Yong Wu <yong.wu@mediatek.com>
> + */
> +#ifndef __DTS_IOMMU_PORT_MT2712_H
> +#define __DTS_IOMMU_PORT_MT2712_H
> +
> +#define MTK_M4U_ID(larb, port) (((larb) << 5) | (port))
> +
> +#define M4U_LARB0_ID 0
> +#define M4U_LARB1_ID 1
> +#define M4U_LARB2_ID 2
> +#define M4U_LARB3_ID 3
> +#define M4U_LARB4_ID 4
> +#define M4U_LARB5_ID 5
> +#define M4U_LARB6_ID 6
> +#define M4U_LARB7_ID 7
> +#define M4U_LARB8_ID 8
> +#define M4U_LARB9_ID 9
> +
> +/* larb0 */
> +#define M4U_PORT_DISP_OVL0 MTK_M4U_ID(M4U_LARB0_ID, 0)
> +#define M4U_PORT_DISP_RDMA0 MTK_M4U_ID(M4U_LARB0_ID, 1)
> +#define M4U_PORT_DISP_WDMA0 MTK_M4U_ID(M4U_LARB0_ID, 2)
> +#define M4U_PORT_DISP_OD_R MTK_M4U_ID(M4U_LARB0_ID, 3)
> +#define M4U_PORT_DISP_OD_W MTK_M4U_ID(M4U_LARB0_ID, 4)
> +#define M4U_PORT_MDP_RDMA0 MTK_M4U_ID(M4U_LARB0_ID, 5)
> +#define M4U_PORT_MDP_WDMA MTK_M4U_ID(M4U_LARB0_ID, 6)
> +#define M4U_PORT_DISP_RDMA2 MTK_M4U_ID(M4U_LARB0_ID, 7)
> +
> +/* larb1 */
> +#define M4U_PORT_HW_VDEC_MC_EXT MTK_M4U_ID(M4U_LARB1_ID, 0)
> +#define M4U_PORT_HW_VDEC_PP_EXT MTK_M4U_ID(M4U_LARB1_ID, 1)
> +#define M4U_PORT_HW_VDEC_UFO_EXT MTK_M4U_ID(M4U_LARB1_ID, 2)
> +#define M4U_PORT_HW_VDEC_VLD_EXT MTK_M4U_ID(M4U_LARB1_ID, 3)
> +#define M4U_PORT_HW_VDEC_VLD2_EXT MTK_M4U_ID(M4U_LARB1_ID, 4)
> +#define M4U_PORT_HW_VDEC_AVC_MV_EXT MTK_M4U_ID(M4U_LARB1_ID, 5)
> +#define M4U_PORT_HW_VDEC_PRED_RD_EXT MTK_M4U_ID(M4U_LARB1_ID, 6)
> +#define M4U_PORT_HW_VDEC_PRED_WR_EXT MTK_M4U_ID(M4U_LARB1_ID, 7)
> +#define M4U_PORT_HW_VDEC_PPWRAP_EXT MTK_M4U_ID(M4U_LARB1_ID, 8)
> +#define M4U_PORT_HW_VDEC_TILE MTK_M4U_ID(M4U_LARB1_ID, 9)
> +#define M4U_PORT_HW_IMG_RESZ_EXT MTK_M4U_ID(M4U_LARB1_ID, 10)
> +
> +/* larb2 */
> +#define M4U_PORT_CAM_DMA0 MTK_M4U_ID(M4U_LARB2_ID, 0)
> +#define M4U_PORT_CAM_DMA1 MTK_M4U_ID(M4U_LARB2_ID, 1)
> +#define M4U_PORT_CAM_DMA2 MTK_M4U_ID(M4U_LARB2_ID, 2)
> +
> +/* larb3 */
> +#define M4U_PORT_VENC_RCPU MTK_M4U_ID(M4U_LARB3_ID, 0)
> +#define M4U_PORT_VENC_REC MTK_M4U_ID(M4U_LARB3_ID, 1)
> +#define M4U_PORT_VENC_BSDMA MTK_M4U_ID(M4U_LARB3_ID, 2)
> +#define M4U_PORT_VENC_SV_COMV MTK_M4U_ID(M4U_LARB3_ID, 3)
> +#define M4U_PORT_VENC_RD_COMV MTK_M4U_ID(M4U_LARB3_ID, 4)
> +#define M4U_PORT_VENC_CUR_CHROMA MTK_M4U_ID(M4U_LARB3_ID, 5)
> +#define M4U_PORT_VENC_REF_CHROMA MTK_M4U_ID(M4U_LARB3_ID, 6)
> +#define M4U_PORT_VENC_CUR_LUMA MTK_M4U_ID(M4U_LARB3_ID, 7)
> +#define M4U_PORT_VENC_REF_LUMA MTK_M4U_ID(M4U_LARB3_ID, 8)
> +
> +/* larb4 */
> +#define M4U_PORT_DISP_OVL1 MTK_M4U_ID(M4U_LARB4_ID, 0)
> +#define M4U_PORT_DISP_RDMA1 MTK_M4U_ID(M4U_LARB4_ID, 1)
> +#define M4U_PORT_DISP_WDMA1 MTK_M4U_ID(M4U_LARB4_ID, 2)
> +#define M4U_PORT_DISP_OD1_R MTK_M4U_ID(M4U_LARB4_ID, 3)
> +#define M4U_PORT_DISP_OD1_W MTK_M4U_ID(M4U_LARB4_ID, 4)
> +#define M4U_PORT_MDP_RDMA1 MTK_M4U_ID(M4U_LARB4_ID, 5)
> +#define M4U_PORT_MDP_WROT1 MTK_M4U_ID(M4U_LARB4_ID, 6)
> +
> +/* larb5 */
> +#define M4U_PORT_DISP_OVL2 MTK_M4U_ID(M4U_LARB5_ID, 0)
> +#define M4U_PORT_DISP_WDMA2 MTK_M4U_ID(M4U_LARB5_ID, 1)
> +#define M4U_PORT_MDP_RDMA2 MTK_M4U_ID(M4U_LARB5_ID, 2)
> +#define M4U_PORT_MDP_WROT0 MTK_M4U_ID(M4U_LARB5_ID, 3)
> +
> +/* larb6 */
> +#define M4U_PORT_JPGDEC_WDMA_0 MTK_M4U_ID(M4U_LARB6_ID, 0)
> +#define M4U_PORT_JPGDEC_WDMA_1 MTK_M4U_ID(M4U_LARB6_ID, 1)
> +#define M4U_PORT_JPGDEC_BSDMA_0 MTK_M4U_ID(M4U_LARB6_ID, 2)
> +#define M4U_PORT_JPGDEC_BSDMA_1 MTK_M4U_ID(M4U_LARB6_ID, 3)
> +
> +/* larb7 */
> +#define M4U_PORT_MDP_RDMA3 MTK_M4U_ID(M4U_LARB7_ID, 0)
> +#define M4U_PORT_MDP_WROT2 MTK_M4U_ID(M4U_LARB7_ID, 1)
> +
> +/* larb8 */
> +#define M4U_PORT_VDO MTK_M4U_ID(M4U_LARB8_ID, 0)
> +#define M4U_PORT_NR MTK_M4U_ID(M4U_LARB8_ID, 1)
> +#define M4U_PORT_WR_CHANNEL0 MTK_M4U_ID(M4U_LARB8_ID, 2)
> +
> +/* larb9 */
> +#define M4U_PORT_TVD MTK_M4U_ID(M4U_LARB9_ID, 0)
> +#define M4U_PORT_WR_CHANNEL1 MTK_M4U_ID(M4U_LARB9_ID, 1)
> +
> +#endif
^ permalink raw reply
* [PATCH v6 0/2] Add ThunderX2 SoC Performance Monitoring Unit driver
From: Ganapatrao Kulkarni @ 2018-06-21 6:33 UTC (permalink / raw)
To: linux-arm-kernel
This patchset adds PMU driver for Cavium's ThunderX2 SoC UNCORE devices.
The SoC has PMU support in L3 cache controller (L3C) and in the
DDR4 Memory Controller (DMC).
v6:
Rebased to 4.18-rc1
Updated with comments from John Garry[3]
[3] https://lkml.org/lkml/2018/5/17/408
v5:
-Incroporated review comments from Mark Rutland[2]
v4:
-Incroporated review comments from Mark Rutland[1]
[1] https://www.spinics.net/lists/arm-kernel/msg588563.html
[2] https://lkml.org/lkml/2018/4/26/376
v3:
- fixed warning reported by kbuild robot
v2:
- rebased to 4.12-rc1
- Removed Arch VULCAN dependency.
- update SMC call parameters as per latest firmware.
v1:
-Initial patch
Ganapatrao Kulkarni (2):
perf: uncore: Adding documentation for ThunderX2 pmu uncore driver
ThunderX2: Add Cavium ThunderX2 SoC UNCORE PMU driver
Documentation/perf/thunderx2-pmu.txt | 66 +++
drivers/perf/Kconfig | 8 +
drivers/perf/Makefile | 1 +
drivers/perf/thunderx2_pmu.c | 949 +++++++++++++++++++++++++++++++++++
include/linux/cpuhotplug.h | 1 +
5 files changed, 1025 insertions(+)
create mode 100644 Documentation/perf/thunderx2-pmu.txt
create mode 100644 drivers/perf/thunderx2_pmu.c
--
2.9.4
^ permalink raw reply
* [PATCH v6 1/2] perf: uncore: Adding documentation for ThunderX2 pmu uncore driver
From: Ganapatrao Kulkarni @ 2018-06-21 6:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621063338.20093-1-ganapatrao.kulkarni@cavium.com>
Documentation for the UNCORE PMUs on Cavium's ThunderX2 SoC.
The SoC has PMU support in its L3 cache controller (L3C) and in the
DDR4 Memory Controller (DMC).
Signed-off-by: Ganapatrao Kulkarni <ganapatrao.kulkarni@cavium.com>
---
Documentation/perf/thunderx2-pmu.txt | 66 ++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 Documentation/perf/thunderx2-pmu.txt
diff --git a/Documentation/perf/thunderx2-pmu.txt b/Documentation/perf/thunderx2-pmu.txt
new file mode 100644
index 0000000..7d89935
--- /dev/null
+++ b/Documentation/perf/thunderx2-pmu.txt
@@ -0,0 +1,66 @@
+
+Cavium ThunderX2 SoC Performance Monitoring Unit (PMU UNCORE)
+==========================================================================
+
+ThunderX2 SoC PMU consists of independent system wide per Socket PMUs such
+as Level 3 Cache(L3C) and DDR4 Memory Controller(DMC).
+
+It has 8 independent DMC PMUs to capture performance events corresponding
+to 8 channels of DDR4 Memory Controller. There are 16 independent L3C PMUs
+to capture events corresponding to 16 tiles of L3 cache. Each PMU supports
+up to 4 counters.
+
+Counters are independently programmable and can be started and stopped
+individually. Each counter can be set to sample specific perf events.
+Counters are 32 bit and do not support overflow interrupt; they are
+sampled at every 2 seconds. The Counters register access are multiplexed
+across channels of DMC and L3C. The muxing(select channel) is done through
+write to a Secure register using smcc calls.
+
+PMU UNCORE (perf) driver:
+
+The thunderx2-pmu driver registers several perf PMUs for DMC and L3C devices.
+Each of the PMUs provides description of its available events
+and configuration options in sysfs.
+ see /sys/devices/uncore_<l3c_S_X/dmc_S_X/>
+
+S is socket id and X represents channel number.
+Each PMU can be used to sample up to 4 events simultaneously.
+
+The "format" directory describes format of the config (event ID).
+The "events" directory provides configuration templates for all
+supported event types that can be used with perf tool.
+
+For example, "uncore_dmc_0_0/cnt_cycles/" is an
+equivalent of "uncore_dmc_0_0/config=0x1/".
+
+Each perf driver also provides a "cpumask" sysfs attribute, which contains a
+single CPU ID of the processor which is likely to be used to handle all the
+PMU events. It will be the first online CPU from the NUMA node of PMU device.
+
+Example for perf tool use:
+
+perf stat -a -e \
+uncore_dmc_0_0/cnt_cycles/,\
+uncore_dmc_0_1/cnt_cycles/,\
+uncore_dmc_0_2/cnt_cycles/,\
+uncore_dmc_0_3/cnt_cycles/,\
+uncore_dmc_0_4/cnt_cycles/,\
+uncore_dmc_0_5/cnt_cycles/,\
+uncore_dmc_0_6/cnt_cycles/,\
+uncore_dmc_0_7/cnt_cycles/ sleep 1
+
+perf stat -a -e \
+uncore_dmc_0_0/cancelled_read_txns/,\
+uncore_dmc_0_0/cnt_cycles/,\
+uncore_dmc_0_0/consumed_read_txns/,\
+uncore_dmc_0_0/data_transfers/ sleep 1
+
+perf stat -a -e \
+uncore_l3c_0_0/l3_retry/,\
+uncore_l3c_0_0/read_hit/,\
+uncore_l3c_0_0/read_request/,\
+uncore_l3c_0_0/inv_request/ sleep 1
+
+The driver does not support sampling, therefore "perf record" will
+not work. Per-task (without "-a") perf sessions are not supported.
--
2.9.4
^ permalink raw reply related
* [PATCH v6 2/2] ThunderX2: Add Cavium ThunderX2 SoC UNCORE PMU driver
From: Ganapatrao Kulkarni @ 2018-06-21 6:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621063338.20093-1-ganapatrao.kulkarni@cavium.com>
This patch adds a perf driver for the PMU UNCORE devices DDR4 Memory
Controller(DMC) and Level 3 Cache(L3C).
ThunderX2 has 8 independent DMC PMUs to capture performance events
corresponding to 8 channels of DDR4 Memory Controller and 16 independent
L3C PMUs to capture events corresponding to 16 tiles of L3 cache.
Each PMU supports up to 4 counters. All counters lack overflow interrupt
and are sampled periodically.
Signed-off-by: Ganapatrao Kulkarni <ganapatrao.kulkarni@cavium.com>
---
drivers/perf/Kconfig | 8 +
drivers/perf/Makefile | 1 +
drivers/perf/thunderx2_pmu.c | 949 +++++++++++++++++++++++++++++++++++++++++++
include/linux/cpuhotplug.h | 1 +
4 files changed, 959 insertions(+)
create mode 100644 drivers/perf/thunderx2_pmu.c
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 08ebaf7..ecedb9e 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -87,6 +87,14 @@ config QCOM_L3_PMU
Adds the L3 cache PMU into the perf events subsystem for
monitoring L3 cache events.
+config THUNDERX2_PMU
+ bool "Cavium ThunderX2 SoC PMU UNCORE"
+ depends on ARCH_THUNDER2 && ARM64 && ACPI
+ help
+ Provides support for ThunderX2 UNCORE events.
+ The SoC has PMU support in its L3 cache controller (L3C) and
+ in the DDR4 Memory Controller (DMC).
+
config XGENE_PMU
depends on ARCH_XGENE
bool "APM X-Gene SoC PMU"
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index b3902bd..909f27f 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o
obj-$(CONFIG_HISI_PMU) += hisilicon/
obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o
obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o
+obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o
obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o
diff --git a/drivers/perf/thunderx2_pmu.c b/drivers/perf/thunderx2_pmu.c
new file mode 100644
index 0000000..676e27e
--- /dev/null
+++ b/drivers/perf/thunderx2_pmu.c
@@ -0,0 +1,949 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CAVIUM THUNDERX2 SoC PMU UNCORE
+ * Copyright (C) 2018 Cavium Inc.
+ * Author: Ganapatrao Kulkarni <gkulkarni@cavium.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/arm-smccc.h>
+#include <linux/cpuhotplug.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+
+/* L3C and DMC has 16 and 8 channels per socket respectively.
+ * Each Channel supports UNCORE PMU device and consists of
+ * 4 independent programmable counters. Counters are 32 bit
+ * and do not support overflow interrupt, they need to be
+ * sampled before overflow(i.e, at every 2 seconds).
+ */
+
+#define UNCORE_MAX_COUNTERS 4
+#define UNCORE_DMC_MAX_CHANNELS 8
+#define UNCORE_L3_MAX_TILES 16
+
+#define UNCORE_HRTIMER_INTERVAL (2 * NSEC_PER_SEC)
+#define GET_EVENTID(ev) ((ev->hw.config) & 0x1ff)
+#define GET_COUNTERID(ev) ((ev->hw.idx) & 0xf)
+#define GET_CHANNELID(pmu_uncore) (pmu_uncore->channel)
+#define DMC_EVENT_CFG(idx, val) ((val) << (((idx) * 8) + 1))
+
+#define L3C_COUNTER_CTL 0xA8
+#define L3C_COUNTER_DATA 0xAC
+#define DMC_COUNTER_CTL 0x234
+#define DMC_COUNTER_DATA 0x240
+
+#define THUNDERX2_SMC_CALL_ID 0xC200FF00
+#define THUNDERX2_SMC_SET_CHANNEL 0xB010
+
+enum thunderx2_uncore_l3_events {
+ L3_EVENT_NONE,
+ L3_EVENT_NBU_CANCEL,
+ L3_EVENT_DIB_RETRY,
+ L3_EVENT_DOB_RETRY,
+ L3_EVENT_DIB_CREDIT_RETRY,
+ L3_EVENT_DOB_CREDIT_RETRY,
+ L3_EVENT_FORCE_RETRY,
+ L3_EVENT_IDX_CONFLICT_RETRY,
+ L3_EVENT_EVICT_CONFLICT_RETRY,
+ L3_EVENT_BANK_CONFLICT_RETRY,
+ L3_EVENT_FILL_ENTRY_RETRY,
+ L3_EVENT_EVICT_NOT_READY_RETRY,
+ L3_EVENT_L3_RETRY,
+ L3_EVENT_READ_REQ,
+ L3_EVENT_WRITE_BACK_REQ,
+ L3_EVENT_INVALIDATE_NWRITE_REQ,
+ L3_EVENT_INV_REQ,
+ L3_EVENT_SELF_REQ,
+ L3_EVENT_REQ,
+ L3_EVENT_EVICT_REQ,
+ L3_EVENT_INVALIDATE_NWRITE_HIT,
+ L3_EVENT_INVALIDATE_HIT,
+ L3_EVENT_SELF_HIT,
+ L3_EVENT_READ_HIT,
+ L3_EVENT_MAX,
+};
+
+enum thunderx2_uncore_dmc_events {
+ DMC_EVENT_NONE,
+ DMC_EVENT_COUNT_CYCLES,
+ DMC_EVENT_RES2,
+ DMC_EVENT_RES3,
+ DMC_EVENT_RES4,
+ DMC_EVENT_RES5,
+ DMC_EVENT_RES6,
+ DMC_EVENT_RES7,
+ DMC_EVENT_RES8,
+ DMC_EVENT_READ_64B_TXNS,
+ DMC_EVENT_READ_BELOW_64B_TXNS,
+ DMC_EVENT_WRITE_TXNS,
+ DMC_EVENT_TXN_CYCLES,
+ DMC_EVENT_DATA_TRANSFERS,
+ DMC_EVENT_CANCELLED_READ_TXNS,
+ DMC_EVENT_CONSUMED_READ_TXNS,
+ DMC_EVENT_MAX,
+};
+
+enum thunderx2_uncore_type {
+ PMU_TYPE_L3C,
+ PMU_TYPE_DMC,
+ PMU_TYPE_INVALID,
+};
+
+/*
+ * pmu on each socket has 2 uncore devices(dmc and l3),
+ * each uncore device has up to 16 channels, each channel can sample
+ * events independently with counters up to 4.
+ */
+struct thunderx2_pmu_uncore_channel {
+ struct pmu pmu;
+ struct hlist_node node;
+ struct thunderx2_pmu_uncore_dev *uncore_dev;
+ int channel;
+ int cpu;
+ DECLARE_BITMAP(active_counters, UNCORE_MAX_COUNTERS);
+ struct perf_event *events[UNCORE_MAX_COUNTERS];
+ struct hrtimer hrtimer;
+ /* to sync counter alloc/release */
+ raw_spinlock_t lock;
+};
+
+struct thunderx2_pmu_uncore_dev {
+ char *name;
+ struct device *dev;
+ enum thunderx2_uncore_type type;
+ void __iomem *base;
+ int node;
+ u32 max_counters;
+ u32 max_channels;
+ u32 max_events;
+ u64 hrtimer_interval;
+ /* this lock synchronizes across channels */
+ raw_spinlock_t lock;
+ const struct attribute_group **attr_groups;
+ void (*init_cntr_base)(struct perf_event *event,
+ struct thunderx2_pmu_uncore_dev *uncore_dev);
+ void (*select_channel)(struct perf_event *event);
+ void (*stop_event)(struct perf_event *event);
+ void (*start_event)(struct perf_event *event, int flags);
+};
+
+static inline struct thunderx2_pmu_uncore_channel *
+pmu_to_thunderx2_pmu_uncore(struct pmu *pmu)
+{
+ return container_of(pmu, struct thunderx2_pmu_uncore_channel, pmu);
+}
+
+/*
+ * sysfs format attributes
+ */
+static ssize_t thunderx2_pmu_format_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr;
+
+ eattr = container_of(attr, struct dev_ext_attribute, attr);
+ return sprintf(buf, "%s\n", (char *) eattr->var);
+}
+
+#define FORMAT_ATTR(_name, _config) \
+ (&((struct dev_ext_attribute[]) { \
+ { \
+ .attr = __ATTR(_name, 0444, thunderx2_pmu_format_show, NULL), \
+ .var = (void *) _config, \
+ } \
+ })[0].attr.attr)
+
+static struct attribute *l3c_pmu_format_attrs[] = {
+ FORMAT_ATTR(event, "config:0-4"),
+ NULL,
+};
+
+static struct attribute *dmc_pmu_format_attrs[] = {
+ FORMAT_ATTR(event, "config:0-4"),
+ NULL,
+};
+
+static const struct attribute_group l3c_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = l3c_pmu_format_attrs,
+};
+
+static const struct attribute_group dmc_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = dmc_pmu_format_attrs,
+};
+
+/*
+ * sysfs event attributes
+ */
+static ssize_t thunderx2_pmu_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr;
+
+ eattr = container_of(attr, struct dev_ext_attribute, attr);
+ return sprintf(buf, "config=0x%lx\n", (unsigned long) eattr->var);
+}
+
+#define EVENT_ATTR(_name, _config) \
+ (&((struct dev_ext_attribute[]) { \
+ { \
+ .attr = __ATTR(_name, 0444, thunderx2_pmu_event_show, NULL), \
+ .var = (void *) _config, \
+ } \
+ })[0].attr.attr)
+
+static struct attribute *l3c_pmu_events_attrs[] = {
+ EVENT_ATTR(nbu_cancel, L3_EVENT_NBU_CANCEL),
+ EVENT_ATTR(dib_retry, L3_EVENT_DIB_RETRY),
+ EVENT_ATTR(dob_retry, L3_EVENT_DOB_RETRY),
+ EVENT_ATTR(dib_credit_retry, L3_EVENT_DIB_CREDIT_RETRY),
+ EVENT_ATTR(dob_credit_retry, L3_EVENT_DOB_CREDIT_RETRY),
+ EVENT_ATTR(force_retry, L3_EVENT_FORCE_RETRY),
+ EVENT_ATTR(idx_conflict_retry, L3_EVENT_IDX_CONFLICT_RETRY),
+ EVENT_ATTR(evict_conflict_retry, L3_EVENT_EVICT_CONFLICT_RETRY),
+ EVENT_ATTR(bank_conflict_retry, L3_EVENT_BANK_CONFLICT_RETRY),
+ EVENT_ATTR(fill_entry_retry, L3_EVENT_FILL_ENTRY_RETRY),
+ EVENT_ATTR(evict_not_ready_retry, L3_EVENT_EVICT_NOT_READY_RETRY),
+ EVENT_ATTR(l3_retry, L3_EVENT_L3_RETRY),
+ EVENT_ATTR(read_request, L3_EVENT_READ_REQ),
+ EVENT_ATTR(write_back_request, L3_EVENT_WRITE_BACK_REQ),
+ EVENT_ATTR(inv_nwrite_request, L3_EVENT_INVALIDATE_NWRITE_REQ),
+ EVENT_ATTR(inv_request, L3_EVENT_INV_REQ),
+ EVENT_ATTR(self_request, L3_EVENT_SELF_REQ),
+ EVENT_ATTR(request, L3_EVENT_REQ),
+ EVENT_ATTR(evict_request, L3_EVENT_EVICT_REQ),
+ EVENT_ATTR(inv_nwrite_hit, L3_EVENT_INVALIDATE_NWRITE_HIT),
+ EVENT_ATTR(inv_hit, L3_EVENT_INVALIDATE_HIT),
+ EVENT_ATTR(self_hit, L3_EVENT_SELF_HIT),
+ EVENT_ATTR(read_hit, L3_EVENT_READ_HIT),
+ NULL,
+};
+
+static struct attribute *dmc_pmu_events_attrs[] = {
+ EVENT_ATTR(cnt_cycles, DMC_EVENT_COUNT_CYCLES),
+ EVENT_ATTR(read_64b_txns, DMC_EVENT_READ_64B_TXNS),
+ EVENT_ATTR(read_below_64b_txns, DMC_EVENT_READ_BELOW_64B_TXNS),
+ EVENT_ATTR(write_txns, DMC_EVENT_WRITE_TXNS),
+ EVENT_ATTR(txn_cycles, DMC_EVENT_TXN_CYCLES),
+ EVENT_ATTR(data_transfers, DMC_EVENT_DATA_TRANSFERS),
+ EVENT_ATTR(cancelled_read_txns, DMC_EVENT_CANCELLED_READ_TXNS),
+ EVENT_ATTR(consumed_read_txns, DMC_EVENT_CONSUMED_READ_TXNS),
+ NULL,
+};
+
+static const struct attribute_group l3c_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = l3c_pmu_events_attrs,
+};
+
+static const struct attribute_group dmc_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = dmc_pmu_events_attrs,
+};
+
+/*
+ * sysfs cpumask attributes
+ */
+static ssize_t cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cpumask cpu_mask;
+ struct thunderx2_pmu_uncore_channel *pmu_uncore =
+ pmu_to_thunderx2_pmu_uncore(dev_get_drvdata(dev));
+
+ cpumask_clear(&cpu_mask);
+ cpumask_set_cpu(pmu_uncore->cpu, &cpu_mask);
+ return cpumap_print_to_pagebuf(true, buf, &cpu_mask);
+}
+static DEVICE_ATTR_RO(cpumask);
+
+static struct attribute *thunderx2_pmu_cpumask_attrs[] = {
+ &dev_attr_cpumask.attr,
+ NULL,
+};
+
+static const struct attribute_group pmu_cpumask_attr_group = {
+ .attrs = thunderx2_pmu_cpumask_attrs,
+};
+
+/*
+ * Per PMU device attribute groups
+ */
+static const struct attribute_group *l3c_pmu_attr_groups[] = {
+ &l3c_pmu_format_attr_group,
+ &pmu_cpumask_attr_group,
+ &l3c_pmu_events_attr_group,
+ NULL
+};
+
+static const struct attribute_group *dmc_pmu_attr_groups[] = {
+ &dmc_pmu_format_attr_group,
+ &pmu_cpumask_attr_group,
+ &dmc_pmu_events_attr_group,
+ NULL
+};
+
+static inline u32 reg_readl(unsigned long addr)
+{
+ return readl((void __iomem *)addr);
+}
+
+static inline void reg_writel(u32 val, unsigned long addr)
+{
+ writel(val, (void __iomem *)addr);
+}
+
+static int alloc_counter(struct thunderx2_pmu_uncore_channel *pmu_uncore)
+{
+ int counter;
+
+ raw_spin_lock(&pmu_uncore->lock);
+ counter = find_first_zero_bit(pmu_uncore->active_counters,
+ pmu_uncore->uncore_dev->max_counters);
+ if (counter == pmu_uncore->uncore_dev->max_counters) {
+ raw_spin_unlock(&pmu_uncore->lock);
+ return -ENOSPC;
+ }
+ set_bit(counter, pmu_uncore->active_counters);
+ raw_spin_unlock(&pmu_uncore->lock);
+ return counter;
+}
+
+static void free_counter(
+ struct thunderx2_pmu_uncore_channel *pmu_uncore, int counter)
+{
+ raw_spin_lock(&pmu_uncore->lock);
+ clear_bit(counter, pmu_uncore->active_counters);
+ raw_spin_unlock(&pmu_uncore->lock);
+}
+
+/*
+ * DMC and L3 counter interface is muxed across all channels.
+ * hence we need to select the channel before accessing counter
+ * data/control registers.
+ *
+ * L3 Tile and DMC channel selection is through SMC call
+ * SMC call arguments,
+ * x0 = THUNDERX2_SMC_CALL_ID (Vendor SMC call Id)
+ * x1 = THUNDERX2_SMC_SET_CHANNEL (Id to set DMC/L3C channel)
+ * x2 = Node id
+ * x3 = DMC(1)/L3C(0)
+ * x4 = channel Id
+ */
+static void uncore_select_channel(struct perf_event *event)
+{
+ struct arm_smccc_res res;
+ struct thunderx2_pmu_uncore_channel *pmu_uncore =
+ pmu_to_thunderx2_pmu_uncore(event->pmu);
+ struct thunderx2_pmu_uncore_dev *uncore_dev =
+ pmu_uncore->uncore_dev;
+
+ arm_smccc_smc(THUNDERX2_SMC_CALL_ID, THUNDERX2_SMC_SET_CHANNEL,
+ uncore_dev->node, uncore_dev->type,
+ pmu_uncore->channel, 0, 0, 0, &res);
+ if (res.a0) {
+ dev_err(uncore_dev->dev,
+ "SMC to Select channel failed for PMU UNCORE[%s]\n",
+ pmu_uncore->uncore_dev->name);
+ }
+}
+
+/* early probe for firmware support */
+static int __init test_uncore_select_channel_early(struct device *dev)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(THUNDERX2_SMC_CALL_ID, THUNDERX2_SMC_SET_CHANNEL,
+ dev_to_node(dev), 0, 0, 0, 0, 0, &res);
+ if (res.a0) {
+ dev_err(dev, "No Firmware support for PMU UNCORE(%d)\n",
+ dev_to_node(dev));
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void uncore_start_event_l3c(struct perf_event *event, int flags)
+{
+ u32 val;
+ struct hw_perf_event *hwc = &event->hw;
+
+ /* event id encoded in bits [07:03] */
+ val = GET_EVENTID(event) << 3;
+ reg_writel(val, hwc->config_base);
+ local64_set(&hwc->prev_count, 0);
+ reg_writel(0, hwc->event_base);
+}
+
+static void uncore_stop_event_l3c(struct perf_event *event)
+{
+ reg_writel(0, event->hw.config_base);
+}
+
+static void uncore_start_event_dmc(struct perf_event *event, int flags)
+{
+ u32 val;
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = GET_COUNTERID(event);
+ int event_type = GET_EVENTID(event);
+
+ /* enable and start counters.
+ * 8 bits for each counter, bits[05:01] of a counter to set event type.
+ */
+ val = reg_readl(hwc->config_base);
+ val &= ~DMC_EVENT_CFG(idx, 0x1f);
+ val |= DMC_EVENT_CFG(idx, event_type);
+ reg_writel(val, hwc->config_base);
+ local64_set(&hwc->prev_count, 0);
+ reg_writel(0, hwc->event_base);
+}
+
+static void uncore_stop_event_dmc(struct perf_event *event)
+{
+ u32 val;
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = GET_COUNTERID(event);
+
+ /* clear event type(bits[05:01]) to stop counter */
+ val = reg_readl(hwc->config_base);
+ val &= ~DMC_EVENT_CFG(idx, 0x1f);
+ reg_writel(val, hwc->config_base);
+}
+
+static void init_cntr_base_l3c(struct perf_event *event,
+ struct thunderx2_pmu_uncore_dev *uncore_dev)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ /* counter ctrl/data reg offset at 8 */
+ hwc->config_base = (unsigned long)uncore_dev->base
+ + L3C_COUNTER_CTL + (8 * GET_COUNTERID(event));
+ hwc->event_base = (unsigned long)uncore_dev->base
+ + L3C_COUNTER_DATA + (8 * GET_COUNTERID(event));
+}
+
+static void init_cntr_base_dmc(struct perf_event *event,
+ struct thunderx2_pmu_uncore_dev *uncore_dev)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ hwc->config_base = (unsigned long)uncore_dev->base
+ + DMC_COUNTER_CTL;
+ /* counter data reg offset at 0xc */
+ hwc->event_base = (unsigned long)uncore_dev->base
+ + DMC_COUNTER_DATA + (0xc * GET_COUNTERID(event));
+}
+
+static void thunderx2_uncore_update(struct perf_event *event)
+{
+ s64 prev, new = 0;
+ u64 delta;
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunderx2_pmu_uncore_channel *pmu_uncore;
+ enum thunderx2_uncore_type type;
+
+ pmu_uncore = pmu_to_thunderx2_pmu_uncore(event->pmu);
+ type = pmu_uncore->uncore_dev->type;
+
+ pmu_uncore->uncore_dev->select_channel(event);
+
+ new = reg_readl(hwc->event_base);
+ prev = local64_xchg(&hwc->prev_count, new);
+
+ /* handles rollover of 32 bit counter */
+ delta = (u32)(((1UL << 32) - prev) + new);
+ local64_add(delta, &event->count);
+}
+
+enum thunderx2_uncore_type get_uncore_device_type(struct acpi_device *adev)
+{
+ int i = 0;
+ struct acpi_uncore_device {
+ __u8 id[ACPI_ID_LEN];
+ enum thunderx2_uncore_type type;
+ } devices[] = {
+ {"CAV901D", PMU_TYPE_L3C},
+ {"CAV901F", PMU_TYPE_DMC},
+ {"", PMU_TYPE_INVALID}
+ };
+
+ while (devices[i].type != PMU_TYPE_INVALID) {
+ if (!strcmp(acpi_device_hid(adev), devices[i].id))
+ return devices[i].type;
+ i++;
+ }
+ return PMU_TYPE_INVALID;
+}
+
+/*
+ * We must NOT create groups containing events from multiple hardware PMUs,
+ * although mixing different software and hardware PMUs is allowed.
+ */
+static bool thunderx2_uncore_validate_event_group(struct perf_event *event)
+{
+ struct pmu *pmu = event->pmu;
+ struct perf_event *leader = event->group_leader;
+ struct perf_event *sibling;
+ int counters = 0;
+
+ if (leader->pmu != event->pmu && !is_software_event(leader))
+ return false;
+
+ for_each_sibling_event(sibling, event->group_leader) {
+ if (is_software_event(sibling))
+ continue;
+ if (sibling->pmu != pmu)
+ return false;
+ counters++;
+ }
+
+ /*
+ * If the group requires more counters than the HW has,
+ * it cannot ever be scheduled.
+ */
+ return counters < UNCORE_MAX_COUNTERS;
+}
+
+static int thunderx2_uncore_event_init(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunderx2_pmu_uncore_channel *pmu_uncore;
+
+ /* Test the event attr type check for PMU enumeration */
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /*
+ * SOC PMU counters are shared across all cores.
+ * Therefore, it does not support per-process mode.
+ * Also, it does not support event sampling mode.
+ */
+ if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+ return -EINVAL;
+
+ /* SOC counters do not have usr/os/guest/host bits */
+ if (event->attr.exclude_user || event->attr.exclude_kernel ||
+ event->attr.exclude_host || event->attr.exclude_guest)
+ return -EINVAL;
+
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ pmu_uncore = pmu_to_thunderx2_pmu_uncore(event->pmu);
+ event->cpu = pmu_uncore->cpu;
+
+ if (event->attr.config >= pmu_uncore->uncore_dev->max_events)
+ return -EINVAL;
+
+ /* store event id */
+ hwc->config = event->attr.config;
+
+ /* Validate the group */
+ if (!thunderx2_uncore_validate_event_group(event))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void thunderx2_uncore_start(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunderx2_pmu_uncore_channel *pmu_uncore;
+ struct thunderx2_pmu_uncore_dev *uncore_dev;
+ unsigned long irqflags;
+
+ hwc->state = 0;
+ pmu_uncore = pmu_to_thunderx2_pmu_uncore(event->pmu);
+ uncore_dev = pmu_uncore->uncore_dev;
+
+ raw_spin_lock_irqsave(&uncore_dev->lock, irqflags);
+ uncore_dev->select_channel(event);
+ uncore_dev->start_event(event, flags);
+ raw_spin_unlock_irqrestore(&uncore_dev->lock, irqflags);
+
+ perf_event_update_userpage(event);
+
+ if (!find_last_bit(pmu_uncore->active_counters,
+ pmu_uncore->uncore_dev->max_counters)) {
+ hrtimer_start(&pmu_uncore->hrtimer,
+ ns_to_ktime(uncore_dev->hrtimer_interval),
+ HRTIMER_MODE_REL_PINNED);
+ }
+}
+
+static void thunderx2_uncore_stop(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunderx2_pmu_uncore_channel *pmu_uncore;
+ struct thunderx2_pmu_uncore_dev *uncore_dev;
+ unsigned long irqflags;
+
+ if (hwc->state & PERF_HES_UPTODATE)
+ return;
+
+ pmu_uncore = pmu_to_thunderx2_pmu_uncore(event->pmu);
+ uncore_dev = pmu_uncore->uncore_dev;
+
+ raw_spin_lock_irqsave(&uncore_dev->lock, irqflags);
+
+ uncore_dev->select_channel(event);
+ uncore_dev->stop_event(event);
+
+ WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+ hwc->state |= PERF_HES_STOPPED;
+ if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+ thunderx2_uncore_update(event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+ raw_spin_unlock_irqrestore(&uncore_dev->lock, irqflags);
+}
+
+static int thunderx2_uncore_add(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunderx2_pmu_uncore_channel *pmu_uncore;
+ struct thunderx2_pmu_uncore_dev *uncore_dev;
+
+ pmu_uncore = pmu_to_thunderx2_pmu_uncore(event->pmu);
+ uncore_dev = pmu_uncore->uncore_dev;
+
+ /* Allocate a free counter */
+ hwc->idx = alloc_counter(pmu_uncore);
+ if (hwc->idx < 0)
+ return -EAGAIN;
+
+ pmu_uncore->events[hwc->idx] = event;
+ /* set counter control and data registers base address */
+ uncore_dev->init_cntr_base(event, uncore_dev);
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (flags & PERF_EF_START)
+ thunderx2_uncore_start(event, flags);
+
+ return 0;
+}
+
+static void thunderx2_uncore_del(struct perf_event *event, int flags)
+{
+ struct thunderx2_pmu_uncore_channel *pmu_uncore =
+ pmu_to_thunderx2_pmu_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+
+ thunderx2_uncore_stop(event, PERF_EF_UPDATE);
+
+ /* clear the assigned counter */
+ free_counter(pmu_uncore, GET_COUNTERID(event));
+
+ perf_event_update_userpage(event);
+ pmu_uncore->events[hwc->idx] = NULL;
+ hwc->idx = -1;
+}
+
+static void thunderx2_uncore_read(struct perf_event *event)
+{
+ unsigned long irqflags;
+ struct thunderx2_pmu_uncore_channel *pmu_uncore =
+ pmu_to_thunderx2_pmu_uncore(event->pmu);
+
+ raw_spin_lock_irqsave(&pmu_uncore->uncore_dev->lock, irqflags);
+ thunderx2_uncore_update(event);
+ raw_spin_unlock_irqrestore(&pmu_uncore->uncore_dev->lock, irqflags);
+}
+
+static enum hrtimer_restart thunderx2_uncore_hrtimer_callback(
+ struct hrtimer *hrt)
+{
+ struct thunderx2_pmu_uncore_channel *pmu_uncore;
+ unsigned long irqflags;
+ int idx;
+ bool restart_timer = false;
+
+ pmu_uncore = container_of(hrt, struct thunderx2_pmu_uncore_channel,
+ hrtimer);
+
+ raw_spin_lock_irqsave(&pmu_uncore->uncore_dev->lock, irqflags);
+ for_each_set_bit(idx, pmu_uncore->active_counters,
+ pmu_uncore->uncore_dev->max_counters) {
+ struct perf_event *event = pmu_uncore->events[idx];
+
+ thunderx2_uncore_update(event);
+ restart_timer = true;
+ }
+ raw_spin_unlock_irqrestore(&pmu_uncore->uncore_dev->lock, irqflags);
+
+ if (restart_timer)
+ hrtimer_forward_now(hrt,
+ ns_to_ktime(
+ pmu_uncore->uncore_dev->hrtimer_interval));
+
+ return restart_timer ? HRTIMER_RESTART : HRTIMER_NORESTART;
+}
+
+static int thunderx2_pmu_uncore_register(
+ struct thunderx2_pmu_uncore_channel *pmu_uncore)
+{
+ struct device *dev = pmu_uncore->uncore_dev->dev;
+ char *name = pmu_uncore->uncore_dev->name;
+ int channel = pmu_uncore->channel;
+
+ /* Perf event registration */
+ pmu_uncore->pmu = (struct pmu) {
+ .attr_groups = pmu_uncore->uncore_dev->attr_groups,
+ .task_ctx_nr = perf_invalid_context,
+ .event_init = thunderx2_uncore_event_init,
+ .add = thunderx2_uncore_add,
+ .del = thunderx2_uncore_del,
+ .start = thunderx2_uncore_start,
+ .stop = thunderx2_uncore_stop,
+ .read = thunderx2_uncore_read,
+ };
+
+ pmu_uncore->pmu.name = devm_kasprintf(dev, GFP_KERNEL,
+ "%s_%d", name, channel);
+
+ return perf_pmu_register(&pmu_uncore->pmu, pmu_uncore->pmu.name, -1);
+}
+
+static int thunderx2_pmu_uncore_add(struct thunderx2_pmu_uncore_dev *uncore_dev,
+ int channel)
+{
+ struct thunderx2_pmu_uncore_channel *pmu_uncore;
+ int ret, cpu;
+
+ pmu_uncore = devm_kzalloc(uncore_dev->dev, sizeof(*pmu_uncore),
+ GFP_KERNEL);
+ if (!pmu_uncore)
+ return -ENOMEM;
+
+ cpu = cpumask_any_and(cpumask_of_node(uncore_dev->node),
+ cpu_online_mask);
+ if (cpu >= nr_cpu_ids)
+ return -EINVAL;
+
+ pmu_uncore->cpu = cpu;
+ pmu_uncore->channel = channel;
+ pmu_uncore->uncore_dev = uncore_dev;
+
+ hrtimer_init(&pmu_uncore->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ pmu_uncore->hrtimer.function = thunderx2_uncore_hrtimer_callback;
+
+ ret = thunderx2_pmu_uncore_register(pmu_uncore);
+ if (ret) {
+ dev_err(uncore_dev->dev, "%s PMU: Failed to init driver\n",
+ uncore_dev->name);
+ return -ENODEV;
+ }
+
+ /* register hotplug callback for the pmu */
+ ret = cpuhp_state_add_instance(
+ CPUHP_AP_PERF_ARM_THUNDERX2_UNCORE_ONLINE,
+ &pmu_uncore->node);
+ if (ret) {
+ dev_err(uncore_dev->dev, "Error %d registering hotplug", ret);
+ return ret;
+ }
+
+ dev_dbg(uncore_dev->dev, "%s PMU UNCORE registered\n",
+ pmu_uncore->pmu.name);
+ return ret;
+}
+
+static struct thunderx2_pmu_uncore_dev *init_pmu_uncore_dev(
+ struct device *dev, acpi_handle handle,
+ struct acpi_device *adev, u32 type)
+{
+ struct thunderx2_pmu_uncore_dev *uncore_dev;
+ void __iomem *base;
+ struct resource res;
+ struct resource_entry *rentry;
+ struct list_head list;
+ int ret;
+
+ INIT_LIST_HEAD(&list);
+ ret = acpi_dev_get_resources(adev, &list, NULL, NULL);
+ if (ret <= 0) {
+ dev_err(dev, "failed to parse _CRS method, error %d\n", ret);
+ return NULL;
+ }
+
+ list_for_each_entry(rentry, &list, node) {
+ if (resource_type(rentry->res) == IORESOURCE_MEM) {
+ res = *rentry->res;
+ break;
+ }
+ }
+
+ if (!rentry->res)
+ return NULL;
+
+ acpi_dev_free_resource_list(&list);
+ base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(base)) {
+ dev_err(dev, "PMU type %d: Fail to map resource\n", type);
+ return NULL;
+ }
+
+ uncore_dev = devm_kzalloc(dev, sizeof(*uncore_dev), GFP_KERNEL);
+ if (!uncore_dev)
+ return NULL;
+
+ uncore_dev->dev = dev;
+ uncore_dev->type = type;
+ uncore_dev->base = base;
+ uncore_dev->node = dev_to_node(dev);
+
+ raw_spin_lock_init(&uncore_dev->lock);
+
+ switch (uncore_dev->type) {
+ case PMU_TYPE_L3C:
+ uncore_dev->max_counters = UNCORE_MAX_COUNTERS;
+ uncore_dev->max_channels = UNCORE_L3_MAX_TILES;
+ uncore_dev->max_events = L3_EVENT_MAX;
+ uncore_dev->hrtimer_interval = UNCORE_HRTIMER_INTERVAL;
+ uncore_dev->attr_groups = l3c_pmu_attr_groups;
+ uncore_dev->name = devm_kasprintf(dev, GFP_KERNEL,
+ "uncore_l3c_%d", uncore_dev->node);
+ uncore_dev->init_cntr_base = init_cntr_base_l3c;
+ uncore_dev->start_event = uncore_start_event_l3c;
+ uncore_dev->stop_event = uncore_stop_event_l3c;
+ uncore_dev->select_channel = uncore_select_channel;
+ break;
+ case PMU_TYPE_DMC:
+ uncore_dev->max_counters = UNCORE_MAX_COUNTERS;
+ uncore_dev->max_channels = UNCORE_DMC_MAX_CHANNELS;
+ uncore_dev->max_events = DMC_EVENT_MAX;
+ uncore_dev->hrtimer_interval = UNCORE_HRTIMER_INTERVAL;
+ uncore_dev->attr_groups = dmc_pmu_attr_groups;
+ uncore_dev->name = devm_kasprintf(dev, GFP_KERNEL,
+ "uncore_dmc_%d", uncore_dev->node);
+ uncore_dev->init_cntr_base = init_cntr_base_dmc;
+ uncore_dev->start_event = uncore_start_event_dmc;
+ uncore_dev->stop_event = uncore_stop_event_dmc;
+ uncore_dev->select_channel = uncore_select_channel;
+ break;
+ case PMU_TYPE_INVALID:
+ devm_kfree(dev, uncore_dev);
+ uncore_dev = NULL;
+ break;
+ }
+
+ return uncore_dev;
+}
+
+static acpi_status thunderx2_pmu_uncore_dev_add(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct thunderx2_pmu_uncore_dev *uncore_dev;
+ struct acpi_device *adev;
+ enum thunderx2_uncore_type type;
+ int channel;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+ if (acpi_bus_get_status(adev) || !adev->status.present)
+ return AE_OK;
+
+ type = get_uncore_device_type(adev);
+ if (type == PMU_TYPE_INVALID)
+ return AE_OK;
+
+ uncore_dev = init_pmu_uncore_dev((struct device *)data, handle,
+ adev, type);
+
+ if (!uncore_dev)
+ return AE_ERROR;
+
+ for (channel = 0; channel < uncore_dev->max_channels; channel++) {
+ if (thunderx2_pmu_uncore_add(uncore_dev, channel)) {
+ /* Can't add the PMU device, abort */
+ return AE_ERROR;
+ }
+ }
+ return AE_OK;
+}
+
+static int thunderx2_uncore_pmu_offline_cpu(unsigned int cpu,
+ struct hlist_node *node)
+{
+ int new_cpu;
+ struct thunderx2_pmu_uncore_channel *pmu_uncore;
+
+ pmu_uncore = hlist_entry_safe(node,
+ struct thunderx2_pmu_uncore_channel, node);
+ if (cpu != pmu_uncore->cpu)
+ return 0;
+
+ new_cpu = cpumask_any_and(
+ cpumask_of_node(pmu_uncore->uncore_dev->node),
+ cpu_online_mask);
+ if (new_cpu >= nr_cpu_ids)
+ return 0;
+
+ pmu_uncore->cpu = new_cpu;
+ perf_pmu_migrate_context(&pmu_uncore->pmu, cpu, new_cpu);
+ return 0;
+}
+
+static const struct acpi_device_id thunderx2_uncore_acpi_match[] = {
+ {"CAV901C", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, thunderx2_uncore_acpi_match);
+
+static int thunderx2_uncore_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ acpi_handle handle;
+ acpi_status status;
+
+ set_dev_node(dev, acpi_get_node(ACPI_HANDLE(dev)));
+
+ /* Make sure firmware supports DMC/L3C set channel smc call */
+ if (test_uncore_select_channel_early(dev))
+ return -ENODEV;
+
+ if (!has_acpi_companion(dev))
+ return -ENODEV;
+
+ handle = ACPI_HANDLE(dev);
+ if (!handle)
+ return -EINVAL;
+
+ /* Walk through the tree for all PMU UNCORE devices */
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ thunderx2_pmu_uncore_dev_add,
+ NULL, dev, NULL);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "failed to probe PMU devices\n");
+ return_ACPI_STATUS(status);
+ }
+
+ dev_info(dev, "node%d: pmu uncore registered\n", dev_to_node(dev));
+ return 0;
+}
+
+static struct platform_driver thunderx2_uncore_driver = {
+ .probe = thunderx2_uncore_probe,
+ .driver = {
+ .name = "thunderx2-uncore-pmu",
+ .acpi_match_table = ACPI_PTR(thunderx2_uncore_acpi_match),
+ },
+};
+
+static int __init register_thunderx2_uncore_driver(void)
+{
+ int ret;
+
+ ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_THUNDERX2_UNCORE_ONLINE,
+ "perf/tx2/uncore:online",
+ NULL,
+ thunderx2_uncore_pmu_offline_cpu);
+ if (ret)
+ return ret;
+
+ return platform_driver_register(&thunderx2_uncore_driver);
+
+}
+device_initcall(register_thunderx2_uncore_driver);
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 8796ba3..eb0c896 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -161,6 +161,7 @@ enum cpuhp_state {
CPUHP_AP_PERF_ARM_L2X0_ONLINE,
CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE,
+ CPUHP_AP_PERF_ARM_THUNDERX2_UNCORE_ONLINE,
CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE,
CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE,
CPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE,
--
2.9.4
^ permalink raw reply related
* [PATCH 1/1] arm64/mm: move {idmap_pg_dir, tramp_pg_dir, swapper_pg_dir} to .rodata section
From: Ard Biesheuvel @ 2018-06-21 6:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621025141.GB11276@toy>
On 21 June 2018 at 04:51, Jun Yao <yaojun8558363@gmail.com> wrote:
> Hi Ard,
>
> On Wed, Jun 20, 2018 at 12:09:49PM +0200, Ard Biesheuvel wrote:
>> On 20 June 2018 at 10:57, Jun Yao <yaojun8558363@gmail.com> wrote:
>> > Move {idmap_pg_dir,tramp_pg_dir,swapper_pg_dir} to .rodata
>> > section. And update the swapper_pg_dir by fixmap.
>> >
>>
>> I think we may be able to get away with not mapping idmap_pg_dir and
>> tramp_pg_dir at all.
>
> I think we need to move tramp_pg_dir to .rodata. The attacker can write
> a block-mapping(AP=01) to tramp_pg_dir and then he can access kernel
> memory.
>
Why does it need to be mapped at all? When do we ever access it from the code?
>> As for swapper_pg_dir, it would indeed be nice if we could keep those
>> mappings read-only most of the time, but I'm not sure how useful this
>> is if we apply it to the root level only.
>
> The purpose of it is to make 'KSMA' harder, where an single arbitrary
> write is used to add a block mapping to the page-tables, giving the
> attacker full access to kernel memory. That's why we just apply it to
> the root level only. If the attacker can arbitrary write multiple times,
> I think it's hard to defend.
>
So the assumption is that the root level is more easy to find?
Otherwise, I'm not sure I understand why being able to write a level 0
entry is so harmful, given that we don't have block mappings at that
level.
>> > @@ -417,12 +421,22 @@ static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start,
>> >
>> > void __init mark_linear_text_alias_ro(void)
>> > {
>> > + unsigned long size;
>> > +
>> > /*
>> > * Remove the write permissions from the linear alias of .text/.rodata
>> > + *
>> > + * We free some pages in .rodata at paging_init(), which generates a
>> > + * hole. And the hole splits .rodata into two pieces.
>> > */
>> > + size = (unsigned long)swapper_pg_dir + PAGE_SIZE - (unsigned long)_text;
>> > update_mapping_prot(__pa_symbol(_text), (unsigned long)lm_alias(_text),
>> > - (unsigned long)__init_begin - (unsigned long)_text,
>> > - PAGE_KERNEL_RO);
>> > + size, PAGE_KERNEL_RO);
>> > +
>> > + size = (unsigned long)__init_begin - (unsigned long)swapper_pg_end;
>> > + update_mapping_prot(__pa_symbol(swapper_pg_end),
>> > + (unsigned long)lm_alias(swapper_pg_end),
>> > + size, PAGE_KERNEL_RO);
>>
>> I don't think this is necessary. Even if some pages are freed, it
>> doesn't harm to keep a read-only alias of them here since the new
>> owner won't access them via this mapping anyway. So we can keep
>> .rodata as a single region.
>
> To be honest, I didn't think of this issue at first. I later found a
> problem when testing the code on qemu:
>
OK, you're right. I missed the fact that this operates on the linear
alias, not the kernel mapping itself.
What I don't like is that we lose the ability to use block mappings
for the entire .rodata section this way. Isn't it possible to move
these pgdirs to the end of the .rodata segment, perhaps by using a
separate input section name and placing that explicitly? We could even
simply forget about freeing those pages, given that [on 4k pages] the
benefit of freeing 12 KB of space is likely to get lost in the
rounding noise anyway [segments are rounded up to 64 KB in size]
> [ 7.027935] Unable to handle kernel write to read-only memory at virtual address ffff800000f42c00
> [ 7.028388] Mem abort info:
> [ 7.028495] ESR = 0x9600004f
> [ 7.028602] Exception class = DABT (current EL), IL = 32 bits
> [ 7.028749] SET = 0, FnV = 0
> [ 7.028837] EA = 0, S1PTW = 0
> [ 7.028930] Data abort info:
> [ 7.029017] ISV = 0, ISS = 0x0000004f
> [ 7.029120] CM = 0, WnR = 1
> [ 7.029253] swapper pgtable: 4k pages, 48-bit VAs, pgdp = (ptrval)
> [ 7.029418] [ffff800000f42c00] pgd=00000000beff6803, pud=00000000beff5803, pmd=00000000beff3803, pte=00e0000040f42f93
> [ 7.029807] Internal error: Oops: 9600004f [#1] PREEMPT SMP
> [ 7.030027] Modules linked in:
> [ 7.030256] CPU: 0 PID: 1321 Comm: jbd2/vda-8 Not tainted 4.17.0-rc4-02908-g0fe42512b2f0-dirty #71
> [ 7.030486] Hardware name: linux,dummy-virt (DT)
> [ 7.030708] pstate: 40400005 (nZcv daif +PAN -UAO)
> [ 7.030880] pc : __memset+0x16c/0x1c0
> [ 7.030993] lr : jbd2_journal_get_descriptor_buffer+0x7c/0xfc
> [ 7.031134] sp : ffff00000a8ebbe0
> [ 7.031264] x29: ffff00000a8ebbe0 x28: ffff80007c104800
> [ 7.031430] x27: ffff00000a8ebd98 x26: ffff80007c4410d0
> [ 7.031567] x25: ffff80007c441118 x24: 00000000ffffffff
> [ 7.031704] x23: ffff80007c41b000 x22: ffff0000090d9000
> [ 7.031838] x21: 0000000002000000 x20: ffff80007bcee800
> [ 7.031973] x19: ffff80007c4413a8 x18: 0000000000000727
> [ 7.032107] x17: 0000ffff89eba028 x16: ffff0000080e2c38
> [ 7.032286] x15: ffff7e0000000000 x14: 0000000000048018
> [ 7.032424] x13: 0000000048018c00 x12: ffff80007bc65788
> [ 7.032558] x11: ffff00000a8eba68 x10: 0000000000000040
> [ 7.032709] x9 : 0000000000000000 x8 : ffff800000f42c00
> [ 7.032849] x7 : 0000000000000000 x6 : 000000000000003f
> [ 7.032984] x5 : 0000000000000040 x4 : 0000000000000000
> [ 7.033119] x3 : 0000000000000004 x2 : 00000000000003c0
> [ 7.033254] x1 : 0000000000000000 x0 : ffff800000f42c00
> [ 7.033414] Process jbd2/vda-8 (pid: 1321, stack limit = 0x (ptrval))
> [ 7.033633] Call trace:
> [ 7.033757] __memset+0x16c/0x1c0
> [ 7.033858] journal_submit_commit_record+0x60/0x174
> [ 7.033985] jbd2_journal_commit_transaction+0xf38/0x1330
> [ 7.034115] kjournald2+0xcc/0x250
> [ 7.034207] kthread+0xfc/0x128
> [ 7.034295] ret_from_fork+0x10/0x18
> [ 7.034718] Code: 91010108 54ffff4a 8b040108 cb050042 (d50b7428)
> [ 7.035104] ---[ end trace 26d65a14ae983167 ]---
>
> /sys/kernel/debug/kernel_page_tables shows that:
>
> ---[ Linear Mapping ]---
> 0xffff800000000000-0xffff800000080000 512K PTE RW NX SHD AF NG CON UXN MEM/NORMAL
> 0xffff800000080000-0xffff800000200000 1536K PTE ro NX SHD AF NG UXN MEM/NORMAL
> 0xffff800000200000-0xffff800000e00000 12M PMD RW NX SHD AF NG BLK UXN MEM/NORMAL
> 0xffff800000e00000-0xffff800000fb0000 1728K PTE ro NX SHD AF NG UXN MEM/NORMAL
>
> So I split it into pieces.
>
> Thanks,
>
> Jun
^ permalink raw reply
* [PATCH] pci: fix I/O space page leak
From: Thomas Petazzoni @ 2018-06-21 6:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1ca6adde-a91e-84d0-c7dc-fd01bfd9edcc@cogentembedded.com>
Hello,
On Wed, 20 Jun 2018 20:51:37 +0300, Sergei Shtylyov wrote:
> When testing the R-Car PCIe driver on the Condor board, I noticed that iff
> I left the PCIe PHY driver disabled, the kernel crashed with this BUG:
>
> [ 1.225819] kernel BUG at lib/ioremap.c:72!
> [ 1.230007] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP
> [ 1.235496] Modules linked in:
> [ 1.238561] CPU: 0 PID: 39 Comm: kworker/0:1 Not tainted 4.17.0-dirty #1092
> [ 1.245526] Hardware name: Renesas Condor board based on r8a77980 (DT)
> [ 1.252075] Workqueue: events deferred_probe_work_func
> [ 1.257220] pstate: 80000005 (Nzcv daif -PAN -UAO)
> [ 1.262024] pc : ioremap_page_range+0x370/0x3c8
> [ 1.266558] lr : ioremap_page_range+0x40/0x3c8
> [ 1.271002] sp : ffff000008da39e0
> [ 1.274317] x29: ffff000008da39e0 x28: 00e8000000000f07
> [ 1.279636] x27: ffff7dfffee00000 x26: 0140000000000000
> [ 1.284954] x25: ffff7dfffef00000 x24: 00000000000fe100
> [ 1.290272] x23: ffff80007b906000 x22: ffff000008ab8000
> [ 1.295590] x21: ffff000008bb1d58 x20: ffff7dfffef00000
> [ 1.300909] x19: ffff800009c30fb8 x18: 0000000000000001
> [ 1.306226] x17: 00000000000152d0 x16: 00000000014012d0
> [ 1.311544] x15: 0000000000000000 x14: 0720072007200720
> [ 1.316862] x13: 0720072007200720 x12: 0720072007200720
> [ 1.322180] x11: 0720072007300730 x10: 00000000000000ae
> [ 1.327498] x9 : 0000000000000000 x8 : ffff7dffff000000
> [ 1.332816] x7 : 0000000000000000 x6 : 0000000000000100
> [ 1.338134] x5 : 0000000000000000 x4 : 000000007b906000
> [ 1.343452] x3 : ffff80007c61a880 x2 : ffff7dfffeefffff
> [ 1.348770] x1 : 0000000040000000 x0 : 00e80000fe100f07
> [ 1.354090] Process kworker/0:1 (pid: 39, stack limit = 0x (ptrval))
> [ 1.361056] Call trace:
> [ 1.363504] ioremap_page_range+0x370/0x3c8
> [ 1.367695] pci_remap_iospace+0x7c/0xac
> [ 1.371624] pci_parse_request_of_pci_ranges+0x13c/0x190
> [ 1.376945] rcar_pcie_probe+0x4c/0xb04
> [ 1.380786] platform_drv_probe+0x50/0xbc
> [ 1.384799] driver_probe_device+0x21c/0x308
> [ 1.389072] __device_attach_driver+0x98/0xc8
> [ 1.393431] bus_for_each_drv+0x54/0x94
> [ 1.397269] __device_attach+0xc4/0x12c
> [ 1.401107] device_initial_probe+0x10/0x18
> [ 1.405292] bus_probe_device+0x90/0x98
> [ 1.409130] deferred_probe_work_func+0xb0/0x150
> [ 1.413756] process_one_work+0x12c/0x29c
> [ 1.417768] worker_thread+0x200/0x3fc
> [ 1.421522] kthread+0x108/0x134
> [ 1.424755] ret_from_fork+0x10/0x18
> [ 1.428334] Code: f9004ba2 54000080 aa0003fb 17ffff48 (d4210000)
>
> It turned out that pci_remap_iospace() wasn't undone when the driver's
> probe failed, and since devm_phy_optional_get() returned -EPROBE_DEFER,
> the probe was retried, finally causing the BUG due to trying to remap
> already remapped pages.
>
> The most feasible solution seems to introduce devm_pci_remap_iospace()
> and call it instead of pci_remap_iospace(), so that the pages get unmapped
> automagically on any probe failure.
>
> And while fixing pci_parse_request_of_pci_ranges(), aslo fix the other
> drivers that have probably copied the bad example...
>
> Fixes: 4e64dbe226e7 ("PCI: generic: Expose pci_host_common_probe() for use by other drivers")
> Fixes: cbce7900598c ("PCI: designware: Make driver arch-agnostic")
> Fixes: 8c39d710363c ("PCI: aardvark: Add Aardvark PCI host controller driver")
> Fixes: d3c68e0a7e34 ("PCI: faraday: Add Faraday Technology FTPCI100 PCI Host Bridge driver")
> Fixes: 68a15eb7bd0c ("PCI: v3-semi: Add V3 Semiconductor PCI host driver")
> Fixes: b7e78170efd4 ("PCI: versatile: Add DT-based ARM Versatile PB PCIe host driver")
> Fixes: 5f6b6ccdbe1c ("PCI: xgene: Add APM X-Gene PCIe driver")
> Fixes: 637cfacae96f ("PCI: mediatek: Add MediaTek PCIe host controller support")
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> Cc: stable at vger.kernel.org
>
> ---
> The patch is against the 'master' branch of Bjorn Helgaas' 'pci.git' repo...
> It has only been tested with the R-Car PCIe driver...
>
> drivers/pci/controller/dwc/pcie-designware-host.c | 3 +
> drivers/pci/controller/pci-aardvark.c | 2 -
For the Aardvark chunk:
Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Thanks!
Thomas Petazzoni
--
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH 2/2] arm64: dts: exynos: Remove unneeded DSI and DECON address/size cells in Exynos5433
From: Krzysztof Kozlowski @ 2018-06-21 7:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621055923eucas1p190f716475dcd44f72b24abfa4d948c82~6F2j2EPNk0295402954eucas1p1v@eucas1p1.samsung.com>
On 21 June 2018 at 07:59, Andrzej Hajda <a.hajda@samsung.com> wrote:
> On 20.06.2018 21:34, Krzysztof Kozlowski wrote:
>> On Tue, Jun 19, 2018 at 09:59:04AM +0200, Krzysztof Kozlowski wrote:
>>> On 19 June 2018 at 09:26, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>>>> Hi Krzysztof,
>>>>
>>>> On 2018-06-18 19:42, Krzysztof Kozlowski wrote:
>>>>> The decon, decon_tv and dsi nodes have only one child port so
>>>>> address/size mappings are not necessary. This fixes DTC warnings like:
>>>>>
>>>>> Warning (graph_child_address): /soc/decon at 13800000/ports:
>>>>> graph node has single child node 'port at 0', #address-cells/#size-cells are not necessary
>>>>>
>>>>> Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
>>>> Works fine with current Exynos DRM Decon/MIC/DSI drivers.
>>>>
>>>> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
>>> Thanks for review and testing!
>> I have second thoughs whether this patch is correct. AFAIU, the drivers
>> get the remote endpoints by reg==0 (for example the
>> of_graph_get_remote_node() in exynos_dsi_parse_dt()). If the port shall
>> be ignored, then reg==-1 should be passed.
>
> All this is about purity, DECON bindings says explicitly that there
> should be a port with reg=0.
The warnings themself are indeed about purity.... but not having
warnings is quite useful. When you have already warnings either in C
code or in DTC, it is quite easy to skip new ones.
We successfully get rid of all DTC warnings from ARM part. It would be
nice to have the same for ARM64... but not with a cost of making bogus
changes.
> So your patch and DTC warnings are incorrect from bindings PoV.
Good point so this patch should come along with changing of bindings
(and maybe the code as well to use -1 as port/reg).
> On the other side graph bindings are too bloated ( so many lines to
> describe one connection ) so I am happy if there are shrinking attempts :)
> Functionally nothing changes, of graph helpers assume reg=0 if it is not
> present in port/endpoint node.
>
> And regarding real issues, DECON could have more ports, possible candidates:
> - GSCALER0/1/2,
> - GSD/DSD - interconnect between GSCALERs and DECONs,
> - SMIES - image enhancer (not implemented),
> - MIC0/1 - image enhancers,
> - DSIM0/1 - DSI encoders,
> - HDMI - HDMI encoder.
>
> But since all these connections can be configured dynamically, and more
> importantly are inside specific SoC I dont think they need of_graphs. In
> fact I think current of graph is also not necessary, but this is
> different story, removal is on my long TODO list :)
I keep my fingers crossed for this :)
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH V3 1/3] watchdog: stm32: add pclk feature for stm32mp1
From: Ludovic BARRE @ 2018-06-21 7:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180620191409.GA29934@rob-hp-laptop>
On 06/20/2018 09:14 PM, Rob Herring wrote:
> On Wed, Jun 20, 2018 at 03:51:36PM +0200, Ludovic Barre wrote:
>> From: Ludovic Barre <ludovic.barre@st.com>
>>
>> This patch adds config data to manage specific properties by
>> compatible. Adds stm32mp1 config which requires pclk clock.
>>
>> Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
>> ---
>> .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 21 +++-
>
> Please split bindings to separate patch.
OK
>
>> drivers/watchdog/stm32_iwdg.c | 116 +++++++++++++--------
>> 2 files changed, 91 insertions(+), 46 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt
>> index cc13b10a..f07f6d89 100644
>> --- a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt
>> +++ b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt
>> @@ -2,18 +2,31 @@ STM32 Independent WatchDoG (IWDG)
>> ---------------------------------
>>
>> Required properties:
>> -- compatible: "st,stm32-iwdg"
>> -- reg: physical base address and length of the registers set for the device
>> -- clocks: must contain a single entry describing the clock input
>> +- compatible: Should be either "st,stm32-iwdg" or "st,stm32mp1-iwdg"
>
> Please format one per line.
OK
>
>> +- reg: Physical base address and length of the registers set for the device
>> +- clocks: Reference to the clock entry lsi. Additional pclk clock entry
>> + is required only for st,stm32mp1-iwdg.
>> +- clock-names: Name of the clocks used.
>> + "lsi" for st,stm32-iwdg
>> + "pclk", "lsi" for st,stm32mp1-iwdg
>
> Put lsi 1st so it is always index 0.
OK
>
>>
>> Optional Properties:
>> - timeout-sec: Watchdog timeout value in seconds.
>>
>> -Example:
>> +Examples:
>>
>> iwdg: watchdog at 40003000 {
>> compatible = "st,stm32-iwdg";
>> reg = <0x40003000 0x400>;
>> clocks = <&clk_lsi>;
>> + clock-names = "lsi";
>> + timeout-sec = <32>;
>> +};
>> +
>> +iwdg: iwdg at 5a002000 {
>
> watchdog at ...
sorry, I forget this occurrence.
>
> Do we really need 2 example just to show 2 clocks?
No, I could keep only one
>
>> + compatible = "st,stm32mp1-iwdg";
>> + reg = <0x5a002000 0x400>;
>> + clocks = <&rcc IWDG2>, <&clk_lsi>;
>> + clock-names = "pclk", "lsi";
>> timeout-sec = <32>;
>> };
^ permalink raw reply
* Dynamic ftrace self test broken on ARM
From: Stefan Agner @ 2018-06-21 7:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180620212906.24b7b66e@vmware.local.home>
On 21.06.2018 03:29, Steven Rostedt wrote:
> On Thu, 21 Jun 2018 00:07:34 +0100
> Russell King - ARM Linux <linux@armlinux.org.uk> wrote:
>
>
>> > Any input from ARM folks?
>>
>> The same issues must exist on other architectures as ARM is not the only
>> architecture to implement read-only kernel text and dynamic ftrace, so
>> surely this problem isn't unique to ARM.
>
> Probably because of the way set_kernel_text_ro() is implemented in
> other archs. For example, in x86, we have:
>
> void set_kernel_text_ro(void)
> {
> unsigned long start = PFN_ALIGN(_text);
> unsigned long end = PFN_ALIGN(__stop___ex_table);
>
> if (!kernel_set_to_readonly)
> return;
>
> /*
> * Set the kernel identity mapping for text RO.
> */
> set_memory_ro(start, (end - start) >> PAGE_SHIFT);
> }
>
> and arm has:
>
> void set_kernel_text_ro(void)
> {
> set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), true,
> current->active_mm);
> }
>
> Where x86's set_kernel_text_ro() is a nop until the
> kernel_set_to_readonly is set.
>
> Perhaps this may fix things?
>
> [ Not even compiled tested ]
>
> -- Steve
>
> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> index c186474422f3..0cc8e04295a4 100644
> --- a/arch/arm/mm/init.c
> +++ b/arch/arm/mm/init.c
> @@ -736,20 +736,29 @@ static int __mark_rodata_ro(void *unused)
> return 0;
> }
>
> +static int kernel_set_to_readonly __read_mostly;
> +
> void mark_rodata_ro(void)
> {
> + kernel_set_to_readonly = 1;
> stop_machine(__mark_rodata_ro, NULL, NULL);
> debug_checkwx();
> }
>
> void set_kernel_text_rw(void)
> {
> + if (!kernel_set_to_readonly)
> + return;
> +
> set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), false,
> current->active_mm);
> }
>
> void set_kernel_text_ro(void)
> {
> + if (!kernel_set_to_readonly)
> + return;
> +
> set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), true,
> current->active_mm);
> }
This aligns nicely with how this has been solved with commit
162396309745 ("ftrace, x86: make kernel text writable only for
conversions") a while ago.
Reviewed-by: Stefan Agner <stefan@agner.ch>
Compiled and tested here, selftest as well as ftrace at runtime seems to
work fine.
Tested-by: Stefan Agner <stefan@agner.ch>
Thanks Steven! Can you send a patch or should I do it?
--
Stefan
^ permalink raw reply
* [PATCH v7 0/4] ARM: davinci: complete the conversion to using the reset framework
From: Bartosz Golaszewski @ 2018-06-21 7:37 UTC (permalink / raw)
To: linux-arm-kernel
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
These are the remaining patches that still need to be merged in order
to complete the conversion of the davinci dsp driver to using the reset
framework.
They apply on top of v4.18-rc1 with David Lechner's remaining patches
merged.
v1 -> v2:
- fixed the device tree patches the descriptions of which were mixed up
- return -EPROBE_DEFER from davinci-rproc's probe() if we can't get the
reset provider, since it's possible that the lookup table was not yet
registered
- made the local variable naming consistent in the davinci-rproc driver
- fixed a typo in PATCH 5/8
v2 -> v3:
- modify PATCH 1/8: drop the provider argument from the function adding
lookup entries and instead pass the provider name to the RESET_LOOKUP
macro, return -EPROBE_DEFER if we locate a correct lookup entry but
cannot get the corresponding reset controller
- modify the reset lookup entry in psc-da850
- don't manually return -EPROBE_DEFER from davinci-rproc, instead don't
emit an error message if devm_reset_control_get_exclusive() returns
this error code
v3 -> v4:
- make index the second parameter in RESET_LOOKUP() (right after the
provider name)
v4 -> v5:
- fix a bug where the dsp_reset object correctly stored in drproc struct
v5 -> v6:
- rebased on top of v4.17-rc1 and retested
- dropped patches that were applied during 4.17 merge window
- added relevant review and ack tags
v6 -> v7:
- rebased on top of v4.18-rc1 and dropped patches that were applied for
v4.17
Bartosz Golaszewski (4):
remoteproc/davinci: use the reset framework
clk: davinci: kill davinci_clk_reset_assert/deassert()
ARM: davinci: dts: make psc0 a reset provider
ARM: davinci: dts: add a reset control to the dsp node
arch/arm/boot/dts/da850.dtsi | 2 ++
arch/arm/mach-davinci/include/mach/clock.h | 21 -------------
drivers/clk/davinci/psc.c | 18 ------------
drivers/remoteproc/da8xx_remoteproc.c | 34 ++++++++++++++++++----
4 files changed, 31 insertions(+), 44 deletions(-)
delete mode 100644 arch/arm/mach-davinci/include/mach/clock.h
--
2.17.1
^ permalink raw reply
* [PATCH v7 1/4] remoteproc/davinci: use the reset framework
From: Bartosz Golaszewski @ 2018-06-21 7:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621073706.22812-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Switch to using the reset framework instead of handcoded reset routines
we used so far.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: Sekhar Nori <nsekhar@ti.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/remoteproc/da8xx_remoteproc.c | 34 +++++++++++++++++++++++----
1 file changed, 29 insertions(+), 5 deletions(-)
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
index b668e32996e2..76c06b70a1c6 100644
--- a/drivers/remoteproc/da8xx_remoteproc.c
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -10,6 +10,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
+#include <linux/reset.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -20,8 +21,6 @@
#include <linux/platform_device.h>
#include <linux/remoteproc.h>
-#include <mach/clock.h> /* for davinci_clk_reset_assert/deassert() */
-
#include "remoteproc_internal.h"
static char *da8xx_fw_name;
@@ -72,6 +71,7 @@ struct da8xx_rproc {
struct da8xx_rproc_mem *mem;
int num_mems;
struct clk *dsp_clk;
+ struct reset_control *dsp_reset;
void (*ack_fxn)(struct irq_data *data);
struct irq_data *irq_data;
void __iomem *chipsig;
@@ -138,6 +138,7 @@ static int da8xx_rproc_start(struct rproc *rproc)
struct device *dev = rproc->dev.parent;
struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
struct clk *dsp_clk = drproc->dsp_clk;
+ struct reset_control *dsp_reset = drproc->dsp_reset;
int ret;
/* hw requires the start (boot) address be on 1KB boundary */
@@ -155,7 +156,12 @@ static int da8xx_rproc_start(struct rproc *rproc)
return ret;
}
- davinci_clk_reset_deassert(dsp_clk);
+ ret = reset_control_deassert(dsp_reset);
+ if (ret) {
+ dev_err(dev, "reset_control_deassert() failed: %d\n", ret);
+ clk_disable_unprepare(dsp_clk);
+ return ret;
+ }
return 0;
}
@@ -163,8 +169,15 @@ static int da8xx_rproc_start(struct rproc *rproc)
static int da8xx_rproc_stop(struct rproc *rproc)
{
struct da8xx_rproc *drproc = rproc->priv;
+ struct device *dev = rproc->dev.parent;
+ int ret;
+
+ ret = reset_control_assert(drproc->dsp_reset);
+ if (ret) {
+ dev_err(dev, "reset_control_assert() failed: %d\n", ret);
+ return ret;
+ }
- davinci_clk_reset_assert(drproc->dsp_clk);
clk_disable_unprepare(drproc->dsp_clk);
return 0;
@@ -232,6 +245,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
struct resource *bootreg_res;
struct resource *chipsig_res;
struct clk *dsp_clk;
+ struct reset_control *dsp_reset;
void __iomem *chipsig;
void __iomem *bootreg;
int irq;
@@ -268,6 +282,15 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
return PTR_ERR(dsp_clk);
}
+ dsp_reset = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(dsp_reset)) {
+ if (PTR_ERR(dsp_reset) != -EPROBE_DEFER)
+ dev_err(dev, "unable to get reset control: %ld\n",
+ PTR_ERR(dsp_reset));
+
+ return PTR_ERR(dsp_reset);
+ }
+
if (dev->of_node) {
ret = of_reserved_mem_device_init(dev);
if (ret) {
@@ -287,6 +310,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
drproc = rproc->priv;
drproc->rproc = rproc;
drproc->dsp_clk = dsp_clk;
+ drproc->dsp_reset = dsp_reset;
rproc->has_iommu = false;
ret = da8xx_rproc_get_internal_memories(pdev, drproc);
@@ -309,7 +333,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
* *not* in reset, but da8xx_rproc_start() needs the DSP to be
* held in reset at the time it is called.
*/
- ret = davinci_clk_reset_assert(drproc->dsp_clk);
+ ret = reset_control_assert(dsp_reset);
if (ret)
goto free_rproc;
--
2.17.1
^ permalink raw reply related
* [PATCH v7 2/4] clk: davinci: kill davinci_clk_reset_assert/deassert()
From: Bartosz Golaszewski @ 2018-06-21 7:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621073706.22812-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This code is no longer used. Remove it.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: David Lechner <david@lechnology.com>
Acked-by: Stephen Boyd <sboyd@kernel.org>
---
arch/arm/mach-davinci/include/mach/clock.h | 21 ---------------------
drivers/clk/davinci/psc.c | 18 ------------------
2 files changed, 39 deletions(-)
delete mode 100644 arch/arm/mach-davinci/include/mach/clock.h
diff --git a/arch/arm/mach-davinci/include/mach/clock.h b/arch/arm/mach-davinci/include/mach/clock.h
deleted file mode 100644
index 42ed4f2f5ce4..000000000000
--- a/arch/arm/mach-davinci/include/mach/clock.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-davinci/include/mach/clock.h
- *
- * Clock control driver for DaVinci - header file
- *
- * Authors: Vladimir Barinov <source@mvista.com>
- *
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ASM_ARCH_DAVINCI_CLOCK_H
-#define __ASM_ARCH_DAVINCI_CLOCK_H
-
-struct clk;
-
-int davinci_clk_reset_assert(struct clk *c);
-int davinci_clk_reset_deassert(struct clk *c);
-
-#endif
diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c
index fffbed5e263b..5b69e24a224f 100644
--- a/drivers/clk/davinci/psc.c
+++ b/drivers/clk/davinci/psc.c
@@ -303,24 +303,6 @@ static int davinci_lpsc_clk_reset(struct clk *clk, bool reset)
return 0;
}
-/*
- * REVISIT: These exported functions can be removed after a non-DT lookup is
- * added to the reset controller framework and the davinci-rproc driver is
- * updated to use the generic reset controller framework.
- */
-
-int davinci_clk_reset_assert(struct clk *clk)
-{
- return davinci_lpsc_clk_reset(clk, true);
-}
-EXPORT_SYMBOL(davinci_clk_reset_assert);
-
-int davinci_clk_reset_deassert(struct clk *clk)
-{
- return davinci_lpsc_clk_reset(clk, false);
-}
-EXPORT_SYMBOL(davinci_clk_reset_deassert);
-
static int davinci_psc_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
--
2.17.1
^ permalink raw reply related
* [PATCH v7 3/4] ARM: davinci: dts: make psc0 a reset provider
From: Bartosz Golaszewski @ 2018-06-21 7:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621073706.22812-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
The psc driver registers with the reset framework as a provider. Add
the #reset-cells property to the psc0 node.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: David Lechner <david@lechnology.com>
---
arch/arm/boot/dts/da850.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 3fc8b8fd816e..1bc0e4bc0697 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -132,6 +132,7 @@
compatible = "ti,da850-psc0";
reg = <0x10000 0x1000>;
#clock-cells = <1>;
+ #reset-cells = <1>;
#power-domain-cells = <1>;
clocks = <&pll0_sysclk 1>, <&pll0_sysclk 2>,
<&pll0_sysclk 4>, <&pll0_sysclk 6>,
--
2.17.1
^ permalink raw reply related
* [PATCH v7 4/4] ARM: davinci: dts: add a reset control to the dsp node
From: Bartosz Golaszewski @ 2018-06-21 7:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621073706.22812-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
The davinci-rproc driver will soon use the reset framework. Add the
resets property to the dsp node in da850.dtsi.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: David Lechner <david@lechnology.com>
---
arch/arm/boot/dts/da850.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 1bc0e4bc0697..225e0cf4b7bc 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -118,6 +118,7 @@
interrupt-parent = <&intc>;
interrupts = <28>;
clocks = <&psc0 15>;
+ resets = <&psc0 15>;
status = "disabled";
};
soc at 1c00000 {
--
2.17.1
^ permalink raw reply related
* [PATCH V2 3/4] dt-bindings: arm: fsl: add scu binding doc
From: Sascha Hauer @ 2018-06-21 7:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <AM0PR04MB4211C2A376E6C74C7C4AC37880760@AM0PR04MB4211.eurprd04.prod.outlook.com>
On Thu, Jun 21, 2018 at 03:38:30AM +0000, A.s. Dong wrote:
> Hi Rob,
>
> > -----Original Message-----
> > From: Rob Herring [mailto:robh at kernel.org]
> > Sent: Thursday, June 21, 2018 3:45 AM
> > To: A.s. Dong <aisheng.dong@nxp.com>
> > Cc: linux-arm-kernel at lists.infradead.org; dongas86 at gmail.com;
> > kernel at pengutronix.de; shawnguo at kernel.org; Fabio Estevam
> > <fabio.estevam@nxp.com>; dl-linux-imx <linux-imx@nxp.com>; Mark
> > Rutland <mark.rutland@arm.com>; devicetree at vger.kernel.org
> > Subject: Re: [PATCH V2 3/4] dt-bindings: arm: fsl: add scu binding doc
> >
> > On Sun, Jun 17, 2018 at 08:49:48PM +0800, Dong Aisheng wrote:
> > > The System Controller Firmware (SCFW) is a low-level system function
> > > which runs on a dedicated Cortex-M core to provide power, clock, and
> > > resource management. It exists on some i.MX8 processors. e.g. i.MX8QM
> > > (QM, QP), and i.MX8QX (QXP, DX).
> > >
> > > Cc: Shawn Guo <shawnguo@kernel.org>
> > > Cc: Sascha Hauer <kernel@pengutronix.de>
> > > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > > Cc: Rob Herring <robh+dt@kernel.org>
> > > Cc: Mark Rutland <mark.rutland@arm.com>
> > > Cc: devicetree at vger.kernel.org
> > > Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> > > ---
> > > v1->v2:
> > > * remove status
> > > * changed to mu1
> > > ---
> > > .../devicetree/bindings/arm/freescale/fsl,scu.txt | 38
> > > ++++++++++++++++++++++
> > > 1 file changed, 38 insertions(+)
> > > create mode 100644
> > > Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
> > >
> > > diff --git
> > > a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
> > > b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
> > > new file mode 100644
> > > index 0000000..9b7c9fe
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
> > > @@ -0,0 +1,38 @@
> > > +NXP i.MX System Controller Firmware (SCFW)
> > > +--------------------------------------------------------------------
> > > +
> > > +The System Controller Firmware (SCFW) is a low-level system function
> > > +which runs on a dedicated Cortex-M core to provide power, clock, and
> > > +resource management. It exists on some i.MX8 processors. e.g. i.MX8QM
> > > +(QM, QP), and i.MX8QX (QXP, DX).
> > > +
> > > +The AP communicates with the SC using a multi-ported MU module found
> > > +in the LSIO subsystem. The current definition of this MU module
> > > +provides
> > > +5 remote AP connections to the SC to support up to 5 execution
> > > +environments (TZ, HV, standard Linux, etc.). The SC side of this MU
> > > +module interfaces with the LSIO DSC IP bus. The SC firmware will
> > > +communicate with this MU using the MSI bus.
> > > +
> > > +System Controller Device Node:
> > > +=============================
> > > +
> > > +Required properties:
> > > +-------------------
> > > +- compatible: should be "fsl,imx8qxp-scu" or "fsl,imx8qm-scu"
> > > +- fsl,mu: a phandle to the Message Unit used by SCU. Should be
> > > + one of LSIO MU0~M4 for imx8qxp and imx8qm. Users need
> > > + to make sure not use the one which is conflict with
> > > + other execution environments. e.g. ATF.
> >
> > Use the mailbox binding even if you don't use the mailbox subsystem.
> >
>
> Looks reasonable. Will change it.
>
> BTW as I said before, the current mailbox binding fixed #mbox-cells to be
> at least 1 which is not suitable for i.MX SCU MU as it has only one physical
> channel.
Why is that not suitable? If we use #mbox-cells = 1 we can encode the
channel into the second cell. Furthermore, the SCU mode which uses all
channels in a funny way could be another channel id the mu driver could
use to distinguish the different channel/modes. i.e.
#define MU_CHANNEL_0 0
#define MU_CHANNEL_1 1
#define MU_CHANNEL_2 2
#define MU_CHANNEL_3 3
#define MU_CHANNEL_SCU 4
scu {
compatible = "fsl,imx8qxp-scu";
fsl,mu = <&lsio_mu1 MU_CHANNEL_SCU>;
};
This would also allow to the MU-SCU-mode driver to coexist with the
regular MU driver for which Oleksij posted a driver.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH V2 2/4] dt-bindings: arm: fsl: add mu binding doc
From: Sascha Hauer @ 2018-06-21 7:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180620194310.GA28983@rob-hp-laptop>
On Wed, Jun 20, 2018 at 01:43:10PM -0600, Rob Herring wrote:
> On Sun, Jun 17, 2018 at 08:49:47PM +0800, Dong Aisheng wrote:
> > The Messaging Unit module enables two processors within
> > the SoC to communicate and coordinate by passing messages
> > (e.g. data, status and control) through the MU interface.
> >
> > Cc: Shawn Guo <shawnguo@kernel.org>
> > Cc: Sascha Hauer <kernel@pengutronix.de>
> > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > Cc: Rob Herring <robh+dt@kernel.org>
> > Cc: Mark Rutland <mark.rutland@arm.com>
> > Cc: devicetree at vger.kernel.org
> > Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> > ---
> > v1->v2:
> > * typo fixes
> > * remove status property
> > * remove imx6&7 compatible string which may be added later for
> > the generic mailbox binding
> >
> > Note: Because MU used by SCU is not implemented as a mailbox driver,
> > Instead, they're provided in library calls to gain higher performance.
>
> Using a binding doesn't mean you have to use an OS's subsystem.
>
> What needs higher performance? What's the performance difference? Why
> can't the mailbox framework be improved?
>From what I see the performance is improved by polling the interrupt
registers rather than using interrupts.
I see no reason though why this can't be implemented with the mailbox
framework as is.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH v2] iio: adc: at91-sama5d2_adc: add support for oversampling resolution
From: Eugen Hristev @ 2018-06-21 7:56 UTC (permalink / raw)
To: linux-arm-kernel
This implements oversampling support for the SAMA5d2 ADC device.
Enabling oversampling : OSR can improve resolution from 12 bits to
13 or 14 bits.
Changing the channel specification to have 14 bits, and we shift the value
1 bit to the left if we have oversampling for just one extra bit, and two
bits to the left if we have no oversampling (old support).
>From this commit on, the converted values for all the voltage channels
change to 14 bits real data, with most insignificant two bits always zero
if oversampling is not enabled.
sysfs object oversampling_ratio has been enabled and
oversampling_ratio_available will list possible values (1 or 4 or 16) having
1 as default (no oversampling, 1 sample for each conversion).
Special care was required for the triggered buffer scenario (+ DMA), to
adjust the values accordingly.
Touchscreen measurements supported by this driver are not affected by
oversampling, they are still on 12 bits (scale handing is already included
in the driver).
Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
---
Changes in v2:
- updated channel spec to 14 bits as reviewed by Jonathan.
This makes things much simpler, and no more INT_PLUS_MICRO values.
- tidy up the extra line which was forgotten there
- renamed 0SAMPLES macro to 1SAMPLES , which makes more sense (1 sample for
each conversion is the actual number we have). other OSR values are 4SAMPLES
or 16SAMPLES per conversion.
- made code a bit clearer to read by having a per array adjust function
instead of those ugly casts I was using in v1. This is needed to adjust
the values recieved from DMA for each u16 storage bits per conversion (shift
left or not according to OSR setting).
drivers/iio/adc/at91-sama5d2_adc.c | 189 ++++++++++++++++++++++++++++++++-----
1 file changed, 163 insertions(+), 26 deletions(-)
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 58c4c2b..adf1d69 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -130,6 +130,15 @@
#define AT91_SAMA5D2_OVER 0x3c
/* Extended Mode Register */
#define AT91_SAMA5D2_EMR 0x40
+/* Extended Mode Register - Oversampling rate */
+#define AT91_SAMA5D2_EMR_OSR(V) ((V) << 16)
+#define AT91_SAMA5D2_EMR_OSR_MASK GENMASK(17, 16)
+#define AT91_SAMA5D2_EMR_OSR_1SAMPLES 0
+#define AT91_SAMA5D2_EMR_OSR_4SAMPLES 1
+#define AT91_SAMA5D2_EMR_OSR_16SAMPLES 2
+
+/* Extended Mode Register - Averaging on single trigger event */
+#define AT91_SAMA5D2_EMR_ASTE(V) ((V) << 20)
/* Compare Window Register */
#define AT91_SAMA5D2_CWR 0x44
/* Channel Gain Register */
@@ -248,6 +257,11 @@
#define AT91_HWFIFO_MAX_SIZE_STR "128"
#define AT91_HWFIFO_MAX_SIZE 128
+/* Possible values for oversampling ratio */
+#define AT91_OSR_1SAMPLES 1
+#define AT91_OSR_4SAMPLES 4
+#define AT91_OSR_16SAMPLES 16
+
#define AT91_SAMA5D2_CHAN_SINGLE(num, addr) \
{ \
.type = IIO_VOLTAGE, \
@@ -256,12 +270,13 @@
.scan_index = num, \
.scan_type = { \
.sign = 'u', \
- .realbits = 12, \
+ .realbits = 14, \
.storagebits = 16, \
}, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)|\
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.datasheet_name = "CH"#num, \
.indexed = 1, \
}
@@ -276,12 +291,13 @@
.scan_index = num + AT91_SAMA5D2_SINGLE_CHAN_CNT, \
.scan_type = { \
.sign = 's', \
- .realbits = 12, \
+ .realbits = 14, \
.storagebits = 16, \
}, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)|\
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.datasheet_name = "CH"#num"-CH"#num2, \
.indexed = 1, \
}
@@ -299,7 +315,8 @@
.storagebits = 16, \
}, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)|\
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.datasheet_name = name, \
}
#define AT91_SAMA5D2_CHAN_PRESSURE(num, name) \
@@ -313,7 +330,8 @@
.storagebits = 16, \
}, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)|\
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.datasheet_name = name, \
}
@@ -384,6 +402,7 @@ struct at91_adc_state {
const struct iio_chan_spec *chan;
bool conversion_done;
u32 conversion_value;
+ unsigned int oversampling_ratio;
struct at91_adc_soc_info soc_info;
wait_queue_head_t wq_data_available;
struct at91_adc_dma dma_st;
@@ -475,6 +494,77 @@ static inline int at91_adc_of_xlate(struct iio_dev *indio_dev,
return at91_adc_chan_xlate(indio_dev, iiospec->args[0]);
}
+static void at91_adc_config_emr(struct at91_adc_state *st)
+{
+ /* configure the extended mode register */
+ unsigned int emr = at91_adc_readl(st, AT91_SAMA5D2_EMR);
+
+ /* select oversampling per single trigger event */
+ emr |= AT91_SAMA5D2_EMR_ASTE(1);
+
+ /* delete leftover content if it's the case */
+ emr &= ~AT91_SAMA5D2_EMR_OSR_MASK;
+
+ /* select oversampling ratio from configuration */
+ switch (st->oversampling_ratio) {
+ case AT91_OSR_1SAMPLES:
+ emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_1SAMPLES) &
+ AT91_SAMA5D2_EMR_OSR_MASK;
+ break;
+ case AT91_OSR_4SAMPLES:
+ emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_4SAMPLES) &
+ AT91_SAMA5D2_EMR_OSR_MASK;
+ break;
+ case AT91_OSR_16SAMPLES:
+ emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_16SAMPLES) &
+ AT91_SAMA5D2_EMR_OSR_MASK;
+ break;
+ };
+
+ at91_adc_writel(st, AT91_SAMA5D2_EMR, emr);
+}
+
+static int at91_adc_adjust_val_osr(struct at91_adc_state *st, int *val)
+{
+ if (st->oversampling_ratio == AT91_OSR_1SAMPLES) {
+ /*
+ * in this case we only have 12 bits of real data, but channel
+ * is registered as 14 bits, so shift left two bits
+ */
+ *val <<= 2;
+ } else if (st->oversampling_ratio == AT91_OSR_4SAMPLES) {
+ /*
+ * in this case we have 13 bits of real data, but channel
+ * is registered as 14 bits, so left shift one bit
+ */
+ *val <<= 1;
+ }
+
+ return IIO_VAL_INT;
+}
+
+static void at91_adc_adjust_val_osr_array(struct at91_adc_state *st, void *buf,
+ int len)
+{
+ int i = 0, val;
+ u16 *buf_u16 = (u16 *) buf;
+
+ /*
+ * We are converting each two bytes (each sample).
+ * First convert the byte based array to u16, and convert each sample
+ * separately.
+ * Each value is two bytes in an array of chars, so to not shift
+ * more than we need, save the value separately.
+ * len is in bytes, so divide by two to get number of samples.
+ */
+ while (i < len / 2) {
+ val = buf_u16[i];
+ at91_adc_adjust_val_osr(st, &val);
+ buf_u16[i] = val;
+ i++;
+ }
+}
+
static int at91_adc_configure_touch(struct at91_adc_state *st, bool state)
{
u32 clk_khz = st->current_sample_rate / 1000;
@@ -916,6 +1006,7 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
{
struct at91_adc_state *st = iio_priv(indio_dev);
int i = 0;
+ int val;
u8 bit;
for_each_set_bit(bit, indio_dev->active_scan_mask,
@@ -936,7 +1027,9 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
* Thus, emit a warning.
*/
if (chan->type == IIO_VOLTAGE) {
- st->buffer[i] = at91_adc_readl(st, chan->address);
+ val = at91_adc_readl(st, chan->address);
+ at91_adc_adjust_val_osr(st, &val);
+ st->buffer[i] = val;
} else {
st->buffer[i] = 0;
WARN(true, "This trigger cannot handle this type of channel");
@@ -972,6 +1065,14 @@ static void at91_adc_trigger_handler_dma(struct iio_dev *indio_dev)
interval = div_s64((ns - st->dma_st.dma_ts), sample_count);
while (transferred_len >= sample_size) {
+ /*
+ * for all the values in the current sample,
+ * adjust the values inside the buffer for oversampling
+ */
+ at91_adc_adjust_val_osr_array(st,
+ &st->dma_st.rx_buf[st->dma_st.buf_idx],
+ sample_size);
+
iio_push_to_buffers_with_timestamp(indio_dev,
(st->dma_st.rx_buf + st->dma_st.buf_idx),
(st->dma_st.dma_ts + interval * sample_index));
@@ -1212,7 +1313,7 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
- return ret;
+ return at91_adc_adjust_val_osr(st, val);
}
if (chan->type == IIO_PRESSURE) {
ret = iio_device_claim_direct_mode(indio_dev);
@@ -1225,7 +1326,7 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
- return ret;
+ return at91_adc_adjust_val_osr(st, val);
}
/* in this case we have a voltage channel */
@@ -1254,9 +1355,9 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
if (ret > 0) {
*val = st->conversion_value;
+ ret = at91_adc_adjust_val_osr(st, val);
if (chan->scan_type.sign == 's')
*val = sign_extend32(*val, 11);
- ret = IIO_VAL_INT;
st->conversion_done = false;
}
@@ -1292,6 +1393,10 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
*val = at91_adc_get_sample_freq(st);
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = st->oversampling_ratio;
+ return IIO_VAL_INT;
+
default:
return -EINVAL;
}
@@ -1303,16 +1408,28 @@ static int at91_adc_write_raw(struct iio_dev *indio_dev,
{
struct at91_adc_state *st = iio_priv(indio_dev);
- if (mask != IIO_CHAN_INFO_SAMP_FREQ)
- return -EINVAL;
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ if ((val != AT91_OSR_1SAMPLES) && (val != AT91_OSR_4SAMPLES) &&
+ (val != AT91_OSR_16SAMPLES))
+ return -EINVAL;
+ /* if no change, optimize out */
+ if (val == st->oversampling_ratio)
+ return 0;
+ st->oversampling_ratio = val;
+ /* update ratio */
+ at91_adc_config_emr(st);
+ return 0;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (val < st->soc_info.min_sample_rate ||
+ val > st->soc_info.max_sample_rate)
+ return -EINVAL;
- if (val < st->soc_info.min_sample_rate ||
- val > st->soc_info.max_sample_rate)
+ at91_adc_setup_samp_freq(st, val);
+ return 0;
+ default:
return -EINVAL;
-
- at91_adc_setup_samp_freq(st, val);
-
- return 0;
+ };
}
static void at91_adc_dma_init(struct platform_device *pdev)
@@ -1446,14 +1563,6 @@ static int at91_adc_update_scan_mode(struct iio_dev *indio_dev,
return 0;
}
-static const struct iio_info at91_adc_info = {
- .read_raw = &at91_adc_read_raw,
- .write_raw = &at91_adc_write_raw,
- .update_scan_mode = &at91_adc_update_scan_mode,
- .of_xlate = &at91_adc_of_xlate,
- .hwfifo_set_watermark = &at91_adc_set_watermark,
-};
-
static void at91_adc_hw_init(struct at91_adc_state *st)
{
at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
@@ -1466,6 +1575,9 @@ static void at91_adc_hw_init(struct at91_adc_state *st)
AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
+
+ /* configure extended mode register */
+ at91_adc_config_emr(st);
}
static ssize_t at91_adc_get_fifo_state(struct device *dev,
@@ -1496,6 +1608,20 @@ static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
static IIO_CONST_ATTR(hwfifo_watermark_min, "2");
static IIO_CONST_ATTR(hwfifo_watermark_max, AT91_HWFIFO_MAX_SIZE_STR);
+static IIO_CONST_ATTR(oversampling_ratio_available,
+ __stringify(AT91_OSR_1SAMPLES) " "
+ __stringify(AT91_OSR_4SAMPLES) " "
+ __stringify(AT91_OSR_16SAMPLES));
+
+static struct attribute *at91_adc_attributes[] = {
+ &iio_const_attr_oversampling_ratio_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group at91_adc_attribute_group = {
+ .attrs = at91_adc_attributes,
+};
+
static const struct attribute *at91_adc_fifo_attributes[] = {
&iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
&iio_const_attr_hwfifo_watermark_max.dev_attr.attr,
@@ -1504,6 +1630,15 @@ static const struct attribute *at91_adc_fifo_attributes[] = {
NULL,
};
+static const struct iio_info at91_adc_info = {
+ .attrs = &at91_adc_attribute_group,
+ .read_raw = &at91_adc_read_raw,
+ .write_raw = &at91_adc_write_raw,
+ .update_scan_mode = &at91_adc_update_scan_mode,
+ .of_xlate = &at91_adc_of_xlate,
+ .hwfifo_set_watermark = &at91_adc_set_watermark,
+};
+
static int at91_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
@@ -1532,6 +1667,8 @@ static int at91_adc_probe(struct platform_device *pdev)
bitmap_set(&st->touch_st.channels_bitmask,
AT91_SAMA5D2_TOUCH_P_CHAN_IDX, 1);
+ st->oversampling_ratio = AT91_OSR_1SAMPLES;
+
ret = of_property_read_u32(pdev->dev.of_node,
"atmel,min-sample-rate-hz",
&st->soc_info.min_sample_rate);
--
2.7.4
^ permalink raw reply related
* [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts
From: Jon Hunter @ 2018-06-21 8:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180620122042.10950-2-mperttunen@nvidia.com>
On 20/06/18 13:20, Mikko Perttunen wrote:
> HSP interrupts can be routed through exposed "shared interrupts". These
> interrupts can be mapped to various internal interrupt lines. Add
> interrupt properties for shared interrupts to the tegra186-hsp device
> tree bindings. At the same time, add the compatibility string for
> tegra194-hsp, which is backwards compatible with tegra186.
>
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
>
> Notes:
> v2:
> - Edited commit message to not say that doorbell interrupts cannot be
> routed to shared interrupts.
> - Added tegra194 compatibility string.
>
> Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> index b99d25fc2f26..620c249363ca 100644
> --- a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> +++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> @@ -15,12 +15,15 @@ Required properties:
> Array of strings.
> one of:
> - "nvidia,tegra186-hsp"
> + - "nvidia,tegra194-hsp", "nvidia,tegra186-hsp"
> - reg : Offset and length of the register set for the device.
> - interrupt-names
> Array of strings.
> Contains a list of names for the interrupts described by the interrupt
> property. May contain the following entries, in any order:
> - "doorbell"
> + - "sharedN", where 'N' is a number from zero up to the number of
> + external interrupts supported by the HSP instance minus one.
> Users of this binding MUST look up entries in the interrupt property
> by name, using this interrupt-names property to do so.
> - interrupts
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Cheers
Jon
--
nvpublic
^ permalink raw reply
* [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
From: Jon Hunter @ 2018-06-21 8:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180620122042.10950-3-mperttunen@nvidia.com>
On 20/06/18 13:20, Mikko Perttunen wrote:
> Add bindings for the Tegra Combined UART device used to talk to the
> UART console on Tegra194 systems.
>
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
>
> Notes:
> v2:
> - Added Rob's Reviewed-by.
>
> .../bindings/serial/nvidia,tegra194-tcu.txt | 35 ++++++++++++++++++++++
> 1 file changed, 35 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
>
> diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> new file mode 100644
> index 000000000000..a8becf6efd2a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> @@ -0,0 +1,35 @@
> +NVIDIA Tegra Combined UART (TCU)
> +
> +The TCU is a system for sharing a hardware UART instance among multiple
> +systems within the Tegra SoC. It is implemented through a mailbox-
> +based protocol where each "virtual UART" has a pair of mailboxes, one
> +for transmitting and one for receiving, that is used to communicate
> +with the hardware implementing the TCU.
> +
> +Required properties:
> +- name : Should be tcu
> +- compatible
> + Array of strings
> + One of:
> + - "nvidia,tegra194-tcu"
> +- mbox-names:
> + "rx" - Mailbox for receiving data from hardware UART
> + "tx" - Mailbox for transmitting data to hardware UART
> +- mboxes: Mailboxes corresponding to the mbox-names.
> +
> +This node is a mailbox consumer. See the following files for details of
> +the mailbox subsystem, and the specifiers implemented by the relevant
> +provider(s):
> +
> +- .../mailbox/mailbox.txt
> +- .../mailbox/nvidia,tegra186-hsp.txt
> +
> +Example bindings:
> +-----------------
> +
> +tcu: tcu {
> + compatible = "nvidia,tegra194-tcu";
> + mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
> + <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
> + mbox-names = "rx", "tx";
> +};
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Cheers
Jon
--
nvpublic
^ permalink raw reply
* [PATCH v2 4/8] mailbox: tegra-hsp: Refactor in preparation of mailboxes
From: Jon Hunter @ 2018-06-21 8:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180620122042.10950-5-mperttunen@nvidia.com>
On 20/06/18 13:20, Mikko Perttunen wrote:
> The HSP driver is currently in many places written with the assumption
> of only supporting doorbells. Prepare for the addition of shared
> mailbox support by removing these assumptions and cleaning up the code.
>
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
>
> Notes:
> v2:
> - Moved fixes for some style and other issues from the next patch
> here, where they belong.
>
> drivers/mailbox/tegra-hsp.c | 123 +++++++++++++++++++++++++++++---------------
> 1 file changed, 81 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
> index 0cde356c11ab..5dc21a6d01bb 100644
> --- a/drivers/mailbox/tegra-hsp.c
> +++ b/drivers/mailbox/tegra-hsp.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
> + * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
> *
> * This program is free software; you can redistribute it and/or modify it
> * under the terms and conditions of the GNU General Public License,
> @@ -42,6 +42,7 @@ struct tegra_hsp_channel;
> struct tegra_hsp;
>
> struct tegra_hsp_channel {
> + unsigned int type;
> struct tegra_hsp *hsp;
> struct mbox_chan *chan;
> void __iomem *regs;
> @@ -55,6 +56,12 @@ struct tegra_hsp_doorbell {
> unsigned int index;
> };
>
> +static inline struct tegra_hsp_doorbell *
> +channel_to_doorbell(struct tegra_hsp_channel *channel)
> +{
> + return container_of(channel, struct tegra_hsp_doorbell, channel);
> +}
> +
> struct tegra_hsp_db_map {
> const char *name;
> unsigned int master;
> @@ -69,7 +76,7 @@ struct tegra_hsp {
> const struct tegra_hsp_soc *soc;
> struct mbox_controller mbox;
> void __iomem *regs;
> - unsigned int irq;
> + unsigned int doorbell_irq;
> unsigned int num_sm;
> unsigned int num_as;
> unsigned int num_ss;
> @@ -194,7 +201,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
> if (!db)
> return ERR_PTR(-ENOMEM);
>
> - offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
> + offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) * SZ_64K;
> offset += index * 0x100;
>
> db->channel.regs = hsp->regs + offset;
> @@ -218,18 +225,8 @@ static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
> kfree(db);
> }
>
> -static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
> -{
> - struct tegra_hsp_doorbell *db = chan->con_priv;
> -
> - tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
> -
> - return 0;
> -}
> -
> -static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
> +static int tegra_hsp_doorbell_startup(struct tegra_hsp_doorbell *db)
> {
> - struct tegra_hsp_doorbell *db = chan->con_priv;
> struct tegra_hsp *hsp = db->channel.hsp;
> struct tegra_hsp_doorbell *ccplex;
> unsigned long flags;
> @@ -260,9 +257,8 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
> return 0;
> }
>
> -static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
> +static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
> {
> - struct tegra_hsp_doorbell *db = chan->con_priv;
> struct tegra_hsp *hsp = db->channel.hsp;
> struct tegra_hsp_doorbell *ccplex;
> unsigned long flags;
> @@ -281,35 +277,60 @@ static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
> spin_unlock_irqrestore(&hsp->lock, flags);
> }
>
> -static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
> - .send_data = tegra_hsp_doorbell_send_data,
> - .startup = tegra_hsp_doorbell_startup,
> - .shutdown = tegra_hsp_doorbell_shutdown,
> +static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
> +{
> + struct tegra_hsp_channel *channel = chan->con_priv;
> +
> + switch (channel->type) {
> + case TEGRA_HSP_MBOX_TYPE_DB:
> + tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
> + return 0;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int tegra_hsp_startup(struct mbox_chan *chan)
> +{
> + struct tegra_hsp_channel *channel = chan->con_priv;
> +
> + switch (channel->type) {
> + case TEGRA_HSP_MBOX_TYPE_DB:
> + return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
> + }
> +
> + return -EINVAL;
> +}
> +
> +static void tegra_hsp_shutdown(struct mbox_chan *chan)
> +{
> + struct tegra_hsp_channel *channel = chan->con_priv;
> +
> + switch (channel->type) {
> + case TEGRA_HSP_MBOX_TYPE_DB:
> + tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
> + break;
> + }
> +}
> +
> +static const struct mbox_chan_ops tegra_hsp_ops = {
> + .send_data = tegra_hsp_send_data,
> + .startup = tegra_hsp_startup,
> + .shutdown = tegra_hsp_shutdown,
> };
>
> -static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> - const struct of_phandle_args *args)
> +static struct mbox_chan *tegra_hsp_doorbell_xlate(struct tegra_hsp *hsp,
> + unsigned int master)
> {
> struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
> - struct tegra_hsp *hsp = to_tegra_hsp(mbox);
> - unsigned int type = args->args[0];
> - unsigned int master = args->args[1];
> struct tegra_hsp_doorbell *db;
> struct mbox_chan *chan;
> unsigned long flags;
> unsigned int i;
>
> - switch (type) {
> - case TEGRA_HSP_MBOX_TYPE_DB:
> - db = tegra_hsp_doorbell_get(hsp, master);
> - if (db)
> - channel = &db->channel;
> -
> - break;
> -
> - default:
> - break;
> - }
> + db = tegra_hsp_doorbell_get(hsp, master);
> + if (db)
> + channel = &db->channel;
>
> if (IS_ERR(channel))
> return ERR_CAST(channel);
> @@ -321,6 +342,7 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> if (!chan->con_priv) {
> chan->con_priv = channel;
> channel->chan = chan;
> + channel->type = TEGRA_HSP_MBOX_TYPE_DB;
> break;
> }
>
> @@ -332,6 +354,22 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> return chan ?: ERR_PTR(-EBUSY);
> }
>
> +static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> + const struct of_phandle_args *args)
> +{
> + struct tegra_hsp *hsp = to_tegra_hsp(mbox);
> + unsigned int type = args->args[0];
> + unsigned int param = args->args[1];
> +
> + switch (type) {
> + case TEGRA_HSP_MBOX_TYPE_DB:
> + return tegra_hsp_doorbell_xlate(hsp, param);
> +
> + default:
> + return ERR_PTR(-EINVAL);
> + }
> +}
> +
> static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
> {
> struct tegra_hsp_doorbell *db, *tmp;
> @@ -397,14 +435,14 @@ static int tegra_hsp_probe(struct platform_device *pdev)
> return err;
> }
>
> - hsp->irq = err;
> + hsp->doorbell_irq = err;
>
> hsp->mbox.of_xlate = of_tegra_hsp_xlate;
> hsp->mbox.num_chans = 32;
> hsp->mbox.dev = &pdev->dev;
> hsp->mbox.txdone_irq = false;
> hsp->mbox.txdone_poll = false;
> - hsp->mbox.ops = &tegra_hsp_doorbell_ops;
> + hsp->mbox.ops = &tegra_hsp_ops;
>
> hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
> sizeof(*hsp->mbox.chans),
> @@ -427,11 +465,12 @@ static int tegra_hsp_probe(struct platform_device *pdev)
> return err;
> }
>
> - err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
> - IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
> + err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> + tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> + dev_name(&pdev->dev), hsp);
> if (err < 0) {
> - dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
> - hsp->irq, err);
> + dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
> + hsp->doorbell_irq, err);
> return err;
> }
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
Cheers
Jon
--
nvpublic
^ permalink raw reply
* [RESEND PATCH v3 0/3] sh: make early_platform code SuperH-specific
From: Bartosz Golaszewski @ 2018-06-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
I recently started a discussion about the need for a proper early device
probing mechanism[1]. One that would be based on real platform drivers
and support both platform data and device tree.
While we're far from reaching any consensus on the implementation, Arnd
suggested that I start off by moving the SuperH-specific early platform
drivers implementation to arch/sh[2].
This series is the first attempt at making way for a new, less hacky
implementation.
The first patch removes the last instance of a non-sh driver using the
early_platform API. It can be removed since ARM no longer probes early
drivers.
The second patch moves all the early_platform code to arch/sh.
The last patch prefixes all early_platform symbols with 'sh_'.
[1] https://lkml.org/lkml/2018/4/26/657
[2] https://lkml.org/lkml/2018/4/27/239
v1 -> v2:
- certain drivers are compiled for arm/mach-shmobile too - we need to
add ifdefs for CONFIG_SUPERH around early_platform calls
v2 -> v3:
- added a stub for is_early_platform_device() which always returns false
on non-SuperH architectures
RESEND: rebased on top of v4.18-rc1 and verified that there are no build
failures.
Bartosz Golaszewski (3):
clocksource: timer-ti-dm: remove the early platform driver
registration
platform: move the early platform device support to arch/sh
sh: add the sh_ prefix to early platform symbols
arch/sh/drivers/Makefile | 2 +-
arch/sh/drivers/platform_early.c | 346 +++++++++++++++++++++++++
arch/sh/include/asm/platform_early.h | 61 +++++
arch/sh/kernel/cpu/sh2/setup-sh7619.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-mxg.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7201.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7203.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7206.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7264.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7269.c | 3 +-
arch/sh/kernel/cpu/sh3/setup-sh3.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh7705.c | 3 +-
arch/sh/kernel/cpu/sh3/setup-sh770x.c | 3 +-
arch/sh/kernel/cpu/sh3/setup-sh7710.c | 3 +-
arch/sh/kernel/cpu/sh3/setup-sh7720.c | 3 +-
arch/sh/kernel/cpu/sh4/setup-sh4-202.c | 3 +-
arch/sh/kernel/cpu/sh4/setup-sh7750.c | 9 +-
arch/sh/kernel/cpu/sh4/setup-sh7760.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7343.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7366.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7734.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7757.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7763.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7770.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7780.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7785.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7786.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-shx3.c | 3 +-
arch/sh/kernel/cpu/sh5/setup-sh5.c | 3 +-
arch/sh/kernel/setup.c | 3 +-
arch/sh/kernel/time.c | 5 +-
drivers/base/platform.c | 288 --------------------
drivers/clocksource/sh_cmt.c | 13 +-
drivers/clocksource/sh_mtu2.c | 13 +-
drivers/clocksource/sh_tmu.c | 14 +-
drivers/clocksource/timer-ti-dm.c | 1 -
drivers/tty/serial/sh-sci.c | 11 +-
include/linux/platform_device.h | 64 +----
41 files changed, 524 insertions(+), 388 deletions(-)
create mode 100644 arch/sh/drivers/platform_early.c
create mode 100644 arch/sh/include/asm/platform_early.h
--
2.17.1
^ permalink raw reply
* [RESEND PATCH v3 1/3] clocksource: timer-ti-dm: remove the early platform driver registration
From: Bartosz Golaszewski @ 2018-06-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621082321.4259-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This driver is no longer used as an early platform driver. Remove the
registration macro.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
drivers/clocksource/timer-ti-dm.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index 4cce6b224b87..595124074821 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -991,7 +991,6 @@ static struct platform_driver omap_dm_timer_driver = {
},
};
-early_platform_init("earlytimer", &omap_dm_timer_driver);
module_platform_driver(omap_dm_timer_driver);
MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
--
2.17.1
^ permalink raw reply related
* [RESEND PATCH v3 2/3] platform: move the early platform device support to arch/sh
From: Bartosz Golaszewski @ 2018-06-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621082321.4259-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
SuperH is the only user of the current implementation of early platform
device support. We want to introduce a more robust approach to early
probing. As the first step - move all the current early platform code
to arch/sh.
In order not to export internal drivers/base functions to arch code for
this temporary solution - copy the two needed routines for driver
matching from drivers/base/platform.c to arch/sh/drivers/platform_early.c.
Also: call early_platform_cleanup() from subsys_initcall() so that it's
called after all early devices are probed.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
arch/sh/drivers/Makefile | 2 +-
arch/sh/drivers/platform_early.c | 346 +++++++++++++++++++++++++
arch/sh/include/asm/platform_early.h | 61 +++++
arch/sh/kernel/cpu/sh2/setup-sh7619.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-mxg.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7201.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7203.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7206.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7264.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7269.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh3.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh7705.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh770x.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh7710.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh7720.c | 1 +
arch/sh/kernel/cpu/sh4/setup-sh4-202.c | 1 +
arch/sh/kernel/cpu/sh4/setup-sh7750.c | 1 +
arch/sh/kernel/cpu/sh4/setup-sh7760.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7343.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7366.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7734.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7757.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7763.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7770.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7780.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7785.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7786.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-shx3.c | 1 +
arch/sh/kernel/cpu/sh5/setup-sh5.c | 1 +
arch/sh/kernel/setup.c | 1 +
arch/sh/kernel/time.c | 1 +
drivers/base/platform.c | 288 --------------------
drivers/clocksource/sh_cmt.c | 7 +
drivers/clocksource/sh_mtu2.c | 7 +
drivers/clocksource/sh_tmu.c | 8 +
drivers/tty/serial/sh-sci.c | 7 +-
include/linux/platform_device.h | 64 +----
40 files changed, 479 insertions(+), 342 deletions(-)
create mode 100644 arch/sh/drivers/platform_early.c
create mode 100644 arch/sh/include/asm/platform_early.h
diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile
index 3e93b434e604..56b0acace6e7 100644
--- a/arch/sh/drivers/Makefile
+++ b/arch/sh/drivers/Makefile
@@ -3,7 +3,7 @@
# Makefile for the Linux SuperH-specific device drivers.
#
-obj-y += dma/
+obj-y += dma/ platform_early.o
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_SUPERHYWAY) += superhyway/
diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_early.c
new file mode 100644
index 000000000000..bc094f6eb366
--- /dev/null
+++ b/arch/sh/drivers/platform_early.c
@@ -0,0 +1,346 @@
+// SPDX--License-Identifier: GPL-2.0
+
+#include <asm/platform_early.h>
+#include <linux/pm.h>
+
+static __initdata LIST_HEAD(early_platform_driver_list);
+static __initdata LIST_HEAD(early_platform_device_list);
+
+static const struct platform_device_id *
+platform_match_id(const struct platform_device_id *id,
+ struct platform_device *pdev)
+{
+ while (id->name[0]) {
+ if (strcmp(pdev->name, id->name) == 0) {
+ pdev->id_entry = id;
+ return id;
+ }
+ id++;
+ }
+ return NULL;
+}
+
+static int platform_match(struct device *dev, struct device_driver *drv)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct platform_driver *pdrv = to_platform_driver(drv);
+
+ /* When driver_override is set, only bind to the matching driver */
+ if (pdev->driver_override)
+ return !strcmp(pdev->driver_override, drv->name);
+
+ /* Then try to match against the id table */
+ if (pdrv->id_table)
+ return platform_match_id(pdrv->id_table, pdev) != NULL;
+
+ /* fall-back to driver name match */
+ return (strcmp(pdev->name, drv->name) == 0);
+}
+
+#ifdef CONFIG_PM
+static void device_pm_init_common(struct device *dev)
+{
+ if (!dev->power.early_init) {
+ spin_lock_init(&dev->power.lock);
+ dev->power.qos = NULL;
+ dev->power.early_init = true;
+ }
+}
+
+static void pm_runtime_early_init(struct device *dev)
+{
+ dev->power.disable_depth = 1;
+ device_pm_init_common(dev);
+}
+#else
+static void pm_runtime_early_init(struct device *dev) {}
+#endif
+
+/**
+ * early_platform_driver_register - register early platform driver
+ * @epdrv: early_platform driver structure
+ * @buf: string passed from early_param()
+ *
+ * Helper function for early_platform_init() / early_platform_init_buffer()
+ */
+int __init early_platform_driver_register(struct early_platform_driver *epdrv,
+ char *buf)
+{
+ char *tmp;
+ int n;
+
+ /* Simply add the driver to the end of the global list.
+ * Drivers will by default be put on the list in compiled-in order.
+ */
+ if (!epdrv->list.next) {
+ INIT_LIST_HEAD(&epdrv->list);
+ list_add_tail(&epdrv->list, &early_platform_driver_list);
+ }
+
+ /* If the user has specified device then make sure the driver
+ * gets prioritized. The driver of the last device specified on
+ * command line will be put first on the list.
+ */
+ n = strlen(epdrv->pdrv->driver.name);
+ if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
+ list_move(&epdrv->list, &early_platform_driver_list);
+
+ /* Allow passing parameters after device name */
+ if (buf[n] == '\0' || buf[n] == ',')
+ epdrv->requested_id = -1;
+ else {
+ epdrv->requested_id = simple_strtoul(&buf[n + 1],
+ &tmp, 10);
+
+ if (buf[n] != '.' || (tmp == &buf[n + 1])) {
+ epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
+ n = 0;
+ } else
+ n += strcspn(&buf[n + 1], ",") + 1;
+ }
+
+ if (buf[n] == ',')
+ n++;
+
+ if (epdrv->bufsize) {
+ memcpy(epdrv->buffer, &buf[n],
+ min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
+ epdrv->buffer[epdrv->bufsize - 1] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * early_platform_add_devices - adds a number of early platform devices
+ * @devs: array of early platform devices to add
+ * @num: number of early platform devices in array
+ *
+ * Used by early architecture code to register early platform devices and
+ * their platform data.
+ */
+void __init early_platform_add_devices(struct platform_device **devs, int num)
+{
+ struct device *dev;
+ int i;
+
+ /* simply add the devices to list */
+ for (i = 0; i < num; i++) {
+ dev = &devs[i]->dev;
+
+ if (!dev->devres_head.next) {
+ pm_runtime_early_init(dev);
+ INIT_LIST_HEAD(&dev->devres_head);
+ list_add_tail(&dev->devres_head,
+ &early_platform_device_list);
+ }
+ }
+}
+
+/**
+ * early_platform_driver_register_all - register early platform drivers
+ * @class_str: string to identify early platform driver class
+ *
+ * Used by architecture code to register all early platform drivers
+ * for a certain class. If omitted then only early platform drivers
+ * with matching kernel command line class parameters will be registered.
+ */
+void __init early_platform_driver_register_all(char *class_str)
+{
+ /* The "class_str" parameter may or may not be present on the kernel
+ * command line. If it is present then there may be more than one
+ * matching parameter.
+ *
+ * Since we register our early platform drivers using early_param()
+ * we need to make sure that they also get registered in the case
+ * when the parameter is missing from the kernel command line.
+ *
+ * We use parse_early_options() to make sure the early_param() gets
+ * called at least once. The early_param() may be called more than
+ * once since the name of the preferred device may be specified on
+ * the kernel command line. early_platform_driver_register() handles
+ * this case for us.
+ */
+ parse_early_options(class_str);
+}
+
+/**
+ * early_platform_match - find early platform device matching driver
+ * @epdrv: early platform driver structure
+ * @id: id to match against
+ */
+static struct platform_device * __init
+early_platform_match(struct early_platform_driver *epdrv, int id)
+{
+ struct platform_device *pd;
+
+ list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+ if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+ if (pd->id == id)
+ return pd;
+
+ return NULL;
+}
+
+/**
+ * early_platform_left - check if early platform driver has matching devices
+ * @epdrv: early platform driver structure
+ * @id: return true if id or above exists
+ */
+static int __init early_platform_left(struct early_platform_driver *epdrv,
+ int id)
+{
+ struct platform_device *pd;
+
+ list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+ if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+ if (pd->id >= id)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * early_platform_driver_probe_id - probe drivers matching class_str and id
+ * @class_str: string to identify early platform driver class
+ * @id: id to match against
+ * @nr_probe: number of platform devices to successfully probe before exiting
+ */
+static int __init early_platform_driver_probe_id(char *class_str,
+ int id,
+ int nr_probe)
+{
+ struct early_platform_driver *epdrv;
+ struct platform_device *match;
+ int match_id;
+ int n = 0;
+ int left = 0;
+
+ list_for_each_entry(epdrv, &early_platform_driver_list, list) {
+ /* only use drivers matching our class_str */
+ if (strcmp(class_str, epdrv->class_str))
+ continue;
+
+ if (id == -2) {
+ match_id = epdrv->requested_id;
+ left = 1;
+
+ } else {
+ match_id = id;
+ left += early_platform_left(epdrv, id);
+
+ /* skip requested id */
+ switch (epdrv->requested_id) {
+ case EARLY_PLATFORM_ID_ERROR:
+ case EARLY_PLATFORM_ID_UNSET:
+ break;
+ default:
+ if (epdrv->requested_id == id)
+ match_id = EARLY_PLATFORM_ID_UNSET;
+ }
+ }
+
+ switch (match_id) {
+ case EARLY_PLATFORM_ID_ERROR:
+ pr_warn("%s: unable to parse %s parameter\n",
+ class_str, epdrv->pdrv->driver.name);
+ /* fall-through */
+ case EARLY_PLATFORM_ID_UNSET:
+ match = NULL;
+ break;
+ default:
+ match = early_platform_match(epdrv, match_id);
+ }
+
+ if (match) {
+ /*
+ * Set up a sensible init_name to enable
+ * dev_name() and others to be used before the
+ * rest of the driver core is initialized.
+ */
+ if (!match->dev.init_name && slab_is_available()) {
+ if (match->id != -1)
+ match->dev.init_name =
+ kasprintf(GFP_KERNEL, "%s.%d",
+ match->name,
+ match->id);
+ else
+ match->dev.init_name =
+ kasprintf(GFP_KERNEL, "%s",
+ match->name);
+
+ if (!match->dev.init_name)
+ return -ENOMEM;
+ }
+
+ if (epdrv->pdrv->probe(match))
+ pr_warn("%s: unable to probe %s early.\n",
+ class_str, match->name);
+ else
+ n++;
+ }
+
+ if (n >= nr_probe)
+ break;
+ }
+
+ if (left)
+ return n;
+ else
+ return -ENODEV;
+}
+
+/**
+ * early_platform_driver_probe - probe a class of registered drivers
+ * @class_str: string to identify early platform driver class
+ * @nr_probe: number of platform devices to successfully probe before exiting
+ * @user_only: only probe user specified early platform devices
+ *
+ * Used by architecture code to probe registered early platform drivers
+ * within a certain class. For probe to happen a registered early platform
+ * device matching a registered early platform driver is needed.
+ */
+int __init early_platform_driver_probe(char *class_str,
+ int nr_probe,
+ int user_only)
+{
+ int k, n, i;
+
+ n = 0;
+ for (i = -2; n < nr_probe; i++) {
+ k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
+
+ if (k < 0)
+ break;
+
+ n += k;
+
+ if (user_only)
+ break;
+ }
+
+ return n;
+}
+
+/**
+ * early_platform_cleanup - clean up early platform code
+ */
+static int __init early_platform_cleanup(void)
+{
+ struct platform_device *pd, *pd2;
+
+ /* clean up the devres list used to chain devices */
+ list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
+ dev.devres_head) {
+ list_del(&pd->dev.devres_head);
+ memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
+ }
+
+ return 0;
+}
+/*
+ * This must happen once after all early devices are probed but before probing
+ * real platform devices.
+ */
+subsys_initcall(early_platform_cleanup);
diff --git a/arch/sh/include/asm/platform_early.h b/arch/sh/include/asm/platform_early.h
new file mode 100644
index 000000000000..4590ab757d5f
--- /dev/null
+++ b/arch/sh/include/asm/platform_early.h
@@ -0,0 +1,61 @@
+/* SPDX--License-Identifier: GPL-2.0 */
+
+#ifndef __PLATFORM_EARLY__
+#define __PLATFORM_EARLY__
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+struct early_platform_driver {
+ const char *class_str;
+ struct platform_driver *pdrv;
+ struct list_head list;
+ int requested_id;
+ char *buffer;
+ int bufsize;
+};
+
+#define EARLY_PLATFORM_ID_UNSET -2
+#define EARLY_PLATFORM_ID_ERROR -3
+
+extern int early_platform_driver_register(struct early_platform_driver *epdrv,
+ char *buf);
+extern void early_platform_add_devices(struct platform_device **devs, int num);
+
+static inline int is_early_platform_device(struct platform_device *pdev)
+{
+ return !pdev->dev.driver;
+}
+
+extern void early_platform_driver_register_all(char *class_str);
+extern int early_platform_driver_probe(char *class_str,
+ int nr_probe, int user_only);
+
+#define early_platform_init(class_string, platdrv) \
+ early_platform_init_buffer(class_string, platdrv, NULL, 0)
+
+#ifndef MODULE
+#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
+static __initdata struct early_platform_driver early_driver = { \
+ .class_str = class_string, \
+ .buffer = buf, \
+ .bufsize = bufsiz, \
+ .pdrv = platdrv, \
+ .requested_id = EARLY_PLATFORM_ID_UNSET, \
+}; \
+static int __init early_platform_driver_setup_func(char *buffer) \
+{ \
+ return early_platform_driver_register(&early_driver, buffer); \
+} \
+early_param(class_string, early_platform_driver_setup_func)
+#else /* MODULE */
+#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
+static inline char *early_platform_driver_setup_func(void) \
+{ \
+ return bufsiz ? buf : NULL; \
+}
+#endif /* MODULE */
+
+#endif /* __PLATFORM_EARLY__ */
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index d08db08dec38..a02fc03baef8 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -15,6 +15,7 @@
#include <linux/sh_eth.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-mxg.c b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
index 060fdd369f09..d33568a12fad 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-mxg.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
@@ -12,6 +12,7 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
index c1301f68d3cd..b258c5c3af60 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
@@ -14,6 +14,7 @@
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
index 32ec732e28e5..db3f8df8d76d 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
@@ -13,6 +13,7 @@
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index 8d8d354851ce..e1be4fedc739 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -14,6 +14,7 @@
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7264.c b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
index ab71eab690fd..b5bed10d0d72 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
@@ -14,6 +14,7 @@
#include <linux/usb/r8a66597.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7269.c b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
index c7e81b20967c..248a6732397a 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
@@ -15,6 +15,7 @@
#include <linux/usb/r8a66597.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh3.c b/arch/sh/kernel/cpu/sh3/setup-sh3.c
index 53be70b98116..65a83ea4bde4 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh3.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh3.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
/* All SH3 devices are equipped with IRQ0->5 (except sh7708) */
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index f6e392e0d27e..7ec8c11c2f7a 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -17,6 +17,7 @@
#include <linux/sh_intc.h>
#include <asm/rtc.h>
#include <cpu/serial.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
index 59a88611df55..20839dd40a2f 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
@@ -21,6 +21,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <cpu/serial.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index ea52410b430d..780ccd202bab 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -16,6 +16,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <asm/rtc.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
index bf34b4e2e9ef..723bd9c04c8a 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
@@ -22,6 +22,7 @@
#include <linux/sh_intc.h>
#include <linux/usb/ohci_pdriver.h>
#include <asm/rtc.h>
+#include <asm/platform_early.h>
#include <cpu/serial.h>
static struct resource rtc_resources[] = {
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
index 2623f820d510..4a5fa86006cd 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -15,6 +15,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE,
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index 57d30689204d..abb3703c2273 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -16,6 +16,7 @@
#include <linux/sh_intc.h>
#include <linux/serial_sci.h>
#include <generated/machtypes.h>
+#include <asm/platform_early.h>
static struct resource rtc_resources[] = {
[0] = {
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index e51fe1734e13..649f4dcb5935 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -14,6 +14,7 @@
#include <linux/sh_intc.h>
#include <linux/serial_sci.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 5788073a7c30..73715a635048 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
@@ -15,6 +15,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <asm/clock.h>
+#include <asm/platform_early.h>
/* Serial */
static struct plat_sci_port scif0_platform_data = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
index 646918713d9a..942856048112 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
@@ -18,6 +18,7 @@
#include <linux/sh_intc.h>
#include <linux/usb/r8a66597.h>
#include <asm/clock.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index 6b3a26e61abb..bf60456a8012 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -21,6 +21,7 @@
#include <asm/clock.h>
#include <asm/mmzone.h>
#include <asm/siu.h>
+#include <asm/platform_early.h>
#include <cpu/dma-register.h>
#include <cpu/sh7722.h>
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
index 1c1b3c469831..d25d3c3b44ab 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
#include <cpu/sh7723.h>
/* Serial */
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index c20258b18775..0eeadabc8065 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -27,6 +27,7 @@
#include <asm/suspend.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
#include <cpu/dma-register.h>
#include <cpu/sh7724.h>
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
index 8c0c9da6b5b3..bed9d01fa85f 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <asm/clock.h>
#include <asm/irq.h>
+#include <asm/platform_early.h>
#include <cpu/sh7734.h>
/* SCIF */
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index a46a19b49e08..b5b19e81a8dc 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -22,6 +22,7 @@
#include <linux/usb/ohci_pdriver.h>
#include <cpu/dma-register.h>
#include <cpu/sh7757.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_REIE,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
index 40e6cda914d3..51a6c64f860e 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/serial_sci.h>
#include <linux/usb/ohci_pdriver.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
index 82e3bdf2e1b6..77f228e20599 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
@@ -14,6 +14,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE | SCSCR_TOIE,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index d90ff67a4633..c4cbb7584122 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -16,6 +16,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <cpu/dma-register.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE | SCSCR_CKE1,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index b0d6f82f2d71..eda0d61ebf71 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -17,6 +17,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
#include <cpu/dma-register.h>
static struct plat_sci_port scif0_platform_data = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
index 17aac38a6e90..77226a60c36f 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
@@ -26,6 +26,7 @@
#include <linux/usb/ohci_pdriver.h>
#include <cpu/dma-register.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE | SCSCR_CKE1,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index ee14d92d840f..83feaf0a4aae 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -17,6 +17,7 @@
#include <linux/sh_intc.h>
#include <cpu/shx3.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
/*
* This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
diff --git a/arch/sh/kernel/cpu/sh5/setup-sh5.c b/arch/sh/kernel/cpu/sh5/setup-sh5.c
index 084a9cc99175..8ebd26a9fd90 100644
--- a/arch/sh/kernel/cpu/sh5/setup-sh5.c
+++ b/arch/sh/kernel/cpu/sh5/setup-sh5.c
@@ -15,6 +15,7 @@
#include <linux/mm.h>
#include <linux/sh_timer.h>
#include <asm/addrspace.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_IOREMAP,
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index c286cf5da6e7..aed8f331f66b 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -43,6 +43,7 @@
#include <asm/mmu_context.h>
#include <asm/mmzone.h>
#include <asm/sparsemem.h>
+#include <asm/platform_early.h>
/*
* Initialize loops_per_jiffy as 10000000 (1000MIPS).
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index fcd5e41977d1..674d8413491b 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -21,6 +21,7 @@
#include <linux/rtc.h>
#include <asm/clock.h>
#include <asm/rtc.h>
+#include <asm/platform_early.h>
/* Dummy RTC ops */
static void null_rtc_get_time(struct timespec *tv)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index dff82a3c2caa..56bdaacb8666 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -1165,8 +1165,6 @@ int __init platform_bus_init(void)
{
int error;
- early_platform_cleanup();
-
error = device_register(&platform_bus);
if (error) {
put_device(&platform_bus);
@@ -1200,289 +1198,3 @@ u64 dma_get_required_mask(struct device *dev)
}
EXPORT_SYMBOL_GPL(dma_get_required_mask);
#endif
-
-static __initdata LIST_HEAD(early_platform_driver_list);
-static __initdata LIST_HEAD(early_platform_device_list);
-
-/**
- * early_platform_driver_register - register early platform driver
- * @epdrv: early_platform driver structure
- * @buf: string passed from early_param()
- *
- * Helper function for early_platform_init() / early_platform_init_buffer()
- */
-int __init early_platform_driver_register(struct early_platform_driver *epdrv,
- char *buf)
-{
- char *tmp;
- int n;
-
- /* Simply add the driver to the end of the global list.
- * Drivers will by default be put on the list in compiled-in order.
- */
- if (!epdrv->list.next) {
- INIT_LIST_HEAD(&epdrv->list);
- list_add_tail(&epdrv->list, &early_platform_driver_list);
- }
-
- /* If the user has specified device then make sure the driver
- * gets prioritized. The driver of the last device specified on
- * command line will be put first on the list.
- */
- n = strlen(epdrv->pdrv->driver.name);
- if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
- list_move(&epdrv->list, &early_platform_driver_list);
-
- /* Allow passing parameters after device name */
- if (buf[n] == '\0' || buf[n] == ',')
- epdrv->requested_id = -1;
- else {
- epdrv->requested_id = simple_strtoul(&buf[n + 1],
- &tmp, 10);
-
- if (buf[n] != '.' || (tmp == &buf[n + 1])) {
- epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
- n = 0;
- } else
- n += strcspn(&buf[n + 1], ",") + 1;
- }
-
- if (buf[n] == ',')
- n++;
-
- if (epdrv->bufsize) {
- memcpy(epdrv->buffer, &buf[n],
- min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
- epdrv->buffer[epdrv->bufsize - 1] = '\0';
- }
- }
-
- return 0;
-}
-
-/**
- * early_platform_add_devices - adds a number of early platform devices
- * @devs: array of early platform devices to add
- * @num: number of early platform devices in array
- *
- * Used by early architecture code to register early platform devices and
- * their platform data.
- */
-void __init early_platform_add_devices(struct platform_device **devs, int num)
-{
- struct device *dev;
- int i;
-
- /* simply add the devices to list */
- for (i = 0; i < num; i++) {
- dev = &devs[i]->dev;
-
- if (!dev->devres_head.next) {
- pm_runtime_early_init(dev);
- INIT_LIST_HEAD(&dev->devres_head);
- list_add_tail(&dev->devres_head,
- &early_platform_device_list);
- }
- }
-}
-
-/**
- * early_platform_driver_register_all - register early platform drivers
- * @class_str: string to identify early platform driver class
- *
- * Used by architecture code to register all early platform drivers
- * for a certain class. If omitted then only early platform drivers
- * with matching kernel command line class parameters will be registered.
- */
-void __init early_platform_driver_register_all(char *class_str)
-{
- /* The "class_str" parameter may or may not be present on the kernel
- * command line. If it is present then there may be more than one
- * matching parameter.
- *
- * Since we register our early platform drivers using early_param()
- * we need to make sure that they also get registered in the case
- * when the parameter is missing from the kernel command line.
- *
- * We use parse_early_options() to make sure the early_param() gets
- * called at least once. The early_param() may be called more than
- * once since the name of the preferred device may be specified on
- * the kernel command line. early_platform_driver_register() handles
- * this case for us.
- */
- parse_early_options(class_str);
-}
-
-/**
- * early_platform_match - find early platform device matching driver
- * @epdrv: early platform driver structure
- * @id: id to match against
- */
-static struct platform_device * __init
-early_platform_match(struct early_platform_driver *epdrv, int id)
-{
- struct platform_device *pd;
-
- list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
- if (platform_match(&pd->dev, &epdrv->pdrv->driver))
- if (pd->id == id)
- return pd;
-
- return NULL;
-}
-
-/**
- * early_platform_left - check if early platform driver has matching devices
- * @epdrv: early platform driver structure
- * @id: return true if id or above exists
- */
-static int __init early_platform_left(struct early_platform_driver *epdrv,
- int id)
-{
- struct platform_device *pd;
-
- list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
- if (platform_match(&pd->dev, &epdrv->pdrv->driver))
- if (pd->id >= id)
- return 1;
-
- return 0;
-}
-
-/**
- * early_platform_driver_probe_id - probe drivers matching class_str and id
- * @class_str: string to identify early platform driver class
- * @id: id to match against
- * @nr_probe: number of platform devices to successfully probe before exiting
- */
-static int __init early_platform_driver_probe_id(char *class_str,
- int id,
- int nr_probe)
-{
- struct early_platform_driver *epdrv;
- struct platform_device *match;
- int match_id;
- int n = 0;
- int left = 0;
-
- list_for_each_entry(epdrv, &early_platform_driver_list, list) {
- /* only use drivers matching our class_str */
- if (strcmp(class_str, epdrv->class_str))
- continue;
-
- if (id == -2) {
- match_id = epdrv->requested_id;
- left = 1;
-
- } else {
- match_id = id;
- left += early_platform_left(epdrv, id);
-
- /* skip requested id */
- switch (epdrv->requested_id) {
- case EARLY_PLATFORM_ID_ERROR:
- case EARLY_PLATFORM_ID_UNSET:
- break;
- default:
- if (epdrv->requested_id == id)
- match_id = EARLY_PLATFORM_ID_UNSET;
- }
- }
-
- switch (match_id) {
- case EARLY_PLATFORM_ID_ERROR:
- pr_warn("%s: unable to parse %s parameter\n",
- class_str, epdrv->pdrv->driver.name);
- /* fall-through */
- case EARLY_PLATFORM_ID_UNSET:
- match = NULL;
- break;
- default:
- match = early_platform_match(epdrv, match_id);
- }
-
- if (match) {
- /*
- * Set up a sensible init_name to enable
- * dev_name() and others to be used before the
- * rest of the driver core is initialized.
- */
- if (!match->dev.init_name && slab_is_available()) {
- if (match->id != -1)
- match->dev.init_name =
- kasprintf(GFP_KERNEL, "%s.%d",
- match->name,
- match->id);
- else
- match->dev.init_name =
- kasprintf(GFP_KERNEL, "%s",
- match->name);
-
- if (!match->dev.init_name)
- return -ENOMEM;
- }
-
- if (epdrv->pdrv->probe(match))
- pr_warn("%s: unable to probe %s early.\n",
- class_str, match->name);
- else
- n++;
- }
-
- if (n >= nr_probe)
- break;
- }
-
- if (left)
- return n;
- else
- return -ENODEV;
-}
-
-/**
- * early_platform_driver_probe - probe a class of registered drivers
- * @class_str: string to identify early platform driver class
- * @nr_probe: number of platform devices to successfully probe before exiting
- * @user_only: only probe user specified early platform devices
- *
- * Used by architecture code to probe registered early platform drivers
- * within a certain class. For probe to happen a registered early platform
- * device matching a registered early platform driver is needed.
- */
-int __init early_platform_driver_probe(char *class_str,
- int nr_probe,
- int user_only)
-{
- int k, n, i;
-
- n = 0;
- for (i = -2; n < nr_probe; i++) {
- k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
-
- if (k < 0)
- break;
-
- n += k;
-
- if (user_only)
- break;
- }
-
- return n;
-}
-
-/**
- * early_platform_cleanup - clean up early platform code
- */
-void __init early_platform_cleanup(void)
-{
- struct platform_device *pd, *pd2;
-
- /* clean up the devres list used to chain devices */
- list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
- dev.devres_head) {
- list_del(&pd->dev.devres_head);
- memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
- }
-}
-
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index bbbf37c471a3..fe9abe5b3e68 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -33,6 +33,10 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
+#ifdef CONFIG_SUPERH
+#include <asm/platform_early.h>
+#endif
+
struct sh_cmt_device;
/*
@@ -1100,7 +1104,10 @@ static void __exit sh_cmt_exit(void)
platform_driver_unregister(&sh_cmt_device_driver);
}
+#ifdef CONFIG_SUPERH
early_platform_init("earlytimer", &sh_cmt_device_driver);
+#endif
+
subsys_initcall(sh_cmt_init);
module_exit(sh_cmt_exit);
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index 6812e099b6a3..becff3a1a6fb 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -31,6 +31,10 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
+#ifdef CONFIG_SUPERH
+#include <asm/platform_early.h>
+#endif
+
struct sh_mtu2_device;
struct sh_mtu2_channel {
@@ -519,7 +523,10 @@ static void __exit sh_mtu2_exit(void)
platform_driver_unregister(&sh_mtu2_device_driver);
}
+#ifdef CONFIG_SUPERH
early_platform_init("earlytimer", &sh_mtu2_device_driver);
+#endif
+
subsys_initcall(sh_mtu2_init);
module_exit(sh_mtu2_exit);
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index c74a6c543ca2..3f4783a9ecf0 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -32,6 +32,10 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
+#ifdef CONFIG_SUPERH
+#include <asm/platform_early.h>
+#endif
+
enum sh_tmu_model {
SH_TMU,
SH_TMU_SH3,
@@ -626,6 +630,7 @@ static int sh_tmu_probe(struct platform_device *pdev)
pm_runtime_idle(&pdev->dev);
return ret;
}
+
if (is_early_platform_device(pdev))
return 0;
@@ -676,7 +681,10 @@ static void __exit sh_tmu_exit(void)
platform_driver_unregister(&sh_tmu_device_driver);
}
+#ifdef CONFIG_SUPERH
early_platform_init("earlytimer", &sh_tmu_device_driver);
+#endif
+
subsys_initcall(sh_tmu_init);
module_exit(sh_tmu_exit);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index c181eb37f985..a6c3aa7a7de8 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -54,6 +54,7 @@
#ifdef CONFIG_SUPERH
#include <asm/sh_bios.h>
+#include <asm/platform_early.h>
#endif
#include "serial_mctrl_gpio.h"
@@ -2986,6 +2987,7 @@ static struct console serial_console = {
.data = &sci_uart_driver,
};
+#ifdef CONFIG_SUPERH
static struct console early_serial_console = {
.name = "early_ttySC",
.write = serial_console_write,
@@ -3014,6 +3016,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev)
register_console(&early_serial_console);
return 0;
}
+#endif
#define SCI_CONSOLE (&serial_console)
@@ -3216,8 +3219,10 @@ static int sci_probe(struct platform_device *dev)
* the special early probe. We don't have sufficient device state
* to make it beyond this yet.
*/
+#ifdef CONFIG_SUPERH
if (is_early_platform_device(dev))
return sci_probe_earlyprintk(dev);
+#endif
if (dev->dev.of_node) {
p = sci_parse_dt(dev, &dev_id);
@@ -3314,7 +3319,7 @@ static void __exit sci_exit(void)
uart_unregister_driver(&sci_uart_driver);
}
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+#if defined(CONFIG_SUPERH) && defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
early_platform_init_buffer("earlyprintk", &sci_driver,
early_serial_buf, ARRAY_SIZE(early_serial_buf));
#endif
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 3097c943fab9..7d7610da8377 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -284,58 +284,6 @@ void platform_unregister_drivers(struct platform_driver * const *drivers,
#define platform_register_drivers(drivers, count) \
__platform_register_drivers(drivers, count, THIS_MODULE)
-/* early platform driver interface */
-struct early_platform_driver {
- const char *class_str;
- struct platform_driver *pdrv;
- struct list_head list;
- int requested_id;
- char *buffer;
- int bufsize;
-};
-
-#define EARLY_PLATFORM_ID_UNSET -2
-#define EARLY_PLATFORM_ID_ERROR -3
-
-extern int early_platform_driver_register(struct early_platform_driver *epdrv,
- char *buf);
-extern void early_platform_add_devices(struct platform_device **devs, int num);
-
-static inline int is_early_platform_device(struct platform_device *pdev)
-{
- return !pdev->dev.driver;
-}
-
-extern void early_platform_driver_register_all(char *class_str);
-extern int early_platform_driver_probe(char *class_str,
- int nr_probe, int user_only);
-extern void early_platform_cleanup(void);
-
-#define early_platform_init(class_string, platdrv) \
- early_platform_init_buffer(class_string, platdrv, NULL, 0)
-
-#ifndef MODULE
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static __initdata struct early_platform_driver early_driver = { \
- .class_str = class_string, \
- .buffer = buf, \
- .bufsize = bufsiz, \
- .pdrv = platdrv, \
- .requested_id = EARLY_PLATFORM_ID_UNSET, \
-}; \
-static int __init early_platform_driver_setup_func(char *buffer) \
-{ \
- return early_platform_driver_register(&early_driver, buffer); \
-} \
-early_param(class_string, early_platform_driver_setup_func)
-#else /* MODULE */
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static inline char *early_platform_driver_setup_func(void) \
-{ \
- return bufsiz ? buf : NULL; \
-}
-#endif /* MODULE */
-
#ifdef CONFIG_SUSPEND
extern int platform_pm_suspend(struct device *dev);
extern int platform_pm_resume(struct device *dev);
@@ -370,4 +318,16 @@ extern int platform_dma_configure(struct device *dev);
#define USE_PLATFORM_PM_SLEEP_OPS
#endif
+#ifndef CONFIG_SUPERH
+/*
+ * REVISIT: This stub is needed for all non-SuperH users of early platform
+ * drivers. It should go away once we introduce the new platform_device-based
+ * early driver framework.
+ */
+static inline int is_early_platform_device(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif /* CONFIG_SUPERH */
+
#endif /* _PLATFORM_DEVICE_H_ */
--
2.17.1
^ permalink raw reply related
* [RESEND PATCH v3 3/3] sh: add the sh_ prefix to early platform symbols
From: Bartosz Golaszewski @ 2018-06-21 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180621082321.4259-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Old early platform device support is now sh-specific. Before moving on
to implementing new early platform framework based on real platform
devices, prefix all early platform symbols with 'sh_'.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
arch/sh/drivers/platform_early.c | 66 +++++++++++++-------------
arch/sh/include/asm/platform_early.h | 30 ++++++------
arch/sh/kernel/cpu/sh2/setup-sh7619.c | 2 +-
arch/sh/kernel/cpu/sh2a/setup-mxg.c | 2 +-
arch/sh/kernel/cpu/sh2a/setup-sh7201.c | 2 +-
arch/sh/kernel/cpu/sh2a/setup-sh7203.c | 2 +-
arch/sh/kernel/cpu/sh2a/setup-sh7206.c | 2 +-
arch/sh/kernel/cpu/sh2a/setup-sh7264.c | 2 +-
arch/sh/kernel/cpu/sh2a/setup-sh7269.c | 2 +-
arch/sh/kernel/cpu/sh3/setup-sh7705.c | 2 +-
arch/sh/kernel/cpu/sh3/setup-sh770x.c | 2 +-
arch/sh/kernel/cpu/sh3/setup-sh7710.c | 2 +-
arch/sh/kernel/cpu/sh3/setup-sh7720.c | 2 +-
arch/sh/kernel/cpu/sh4/setup-sh4-202.c | 2 +-
arch/sh/kernel/cpu/sh4/setup-sh7750.c | 8 ++--
arch/sh/kernel/cpu/sh4/setup-sh7760.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7343.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7366.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7734.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7757.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7763.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7770.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7780.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7785.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-sh7786.c | 2 +-
arch/sh/kernel/cpu/sh4a/setup-shx3.c | 2 +-
arch/sh/kernel/cpu/sh5/setup-sh5.c | 2 +-
arch/sh/kernel/setup.c | 2 +-
arch/sh/kernel/time.c | 4 +-
drivers/clocksource/sh_cmt.c | 6 +--
drivers/clocksource/sh_mtu2.c | 6 +--
drivers/clocksource/sh_tmu.c | 6 +--
drivers/tty/serial/sh-sci.c | 4 +-
include/linux/platform_device.h | 2 +-
37 files changed, 94 insertions(+), 94 deletions(-)
diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_early.c
index bc094f6eb366..6eba755b8c12 100644
--- a/arch/sh/drivers/platform_early.c
+++ b/arch/sh/drivers/platform_early.c
@@ -3,8 +3,8 @@
#include <asm/platform_early.h>
#include <linux/pm.h>
-static __initdata LIST_HEAD(early_platform_driver_list);
-static __initdata LIST_HEAD(early_platform_device_list);
+static __initdata LIST_HEAD(sh_early_platform_driver_list);
+static __initdata LIST_HEAD(sh_early_platform_device_list);
static const struct platform_device_id *
platform_match_id(const struct platform_device_id *id,
@@ -57,13 +57,13 @@ static void pm_runtime_early_init(struct device *dev) {}
#endif
/**
- * early_platform_driver_register - register early platform driver
- * @epdrv: early_platform driver structure
+ * sh_early_platform_driver_register - register early platform driver
+ * @epdrv: sh_early_platform driver structure
* @buf: string passed from early_param()
*
- * Helper function for early_platform_init() / early_platform_init_buffer()
+ * Helper function for sh_early_platform_init() / sh_early_platform_init_buffer()
*/
-int __init early_platform_driver_register(struct early_platform_driver *epdrv,
+int __init sh_early_platform_driver_register(struct sh_early_platform_driver *epdrv,
char *buf)
{
char *tmp;
@@ -74,7 +74,7 @@ int __init early_platform_driver_register(struct early_platform_driver *epdrv,
*/
if (!epdrv->list.next) {
INIT_LIST_HEAD(&epdrv->list);
- list_add_tail(&epdrv->list, &early_platform_driver_list);
+ list_add_tail(&epdrv->list, &sh_early_platform_driver_list);
}
/* If the user has specified device then make sure the driver
@@ -83,7 +83,7 @@ int __init early_platform_driver_register(struct early_platform_driver *epdrv,
*/
n = strlen(epdrv->pdrv->driver.name);
if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
- list_move(&epdrv->list, &early_platform_driver_list);
+ list_move(&epdrv->list, &sh_early_platform_driver_list);
/* Allow passing parameters after device name */
if (buf[n] == '\0' || buf[n] == ',')
@@ -113,14 +113,14 @@ int __init early_platform_driver_register(struct early_platform_driver *epdrv,
}
/**
- * early_platform_add_devices - adds a number of early platform devices
+ * sh_early_platform_add_devices - adds a number of early platform devices
* @devs: array of early platform devices to add
* @num: number of early platform devices in array
*
* Used by early architecture code to register early platform devices and
* their platform data.
*/
-void __init early_platform_add_devices(struct platform_device **devs, int num)
+void __init sh_early_platform_add_devices(struct platform_device **devs, int num)
{
struct device *dev;
int i;
@@ -133,20 +133,20 @@ void __init early_platform_add_devices(struct platform_device **devs, int num)
pm_runtime_early_init(dev);
INIT_LIST_HEAD(&dev->devres_head);
list_add_tail(&dev->devres_head,
- &early_platform_device_list);
+ &sh_early_platform_device_list);
}
}
}
/**
- * early_platform_driver_register_all - register early platform drivers
+ * sh_early_platform_driver_register_all - register early platform drivers
* @class_str: string to identify early platform driver class
*
* Used by architecture code to register all early platform drivers
* for a certain class. If omitted then only early platform drivers
* with matching kernel command line class parameters will be registered.
*/
-void __init early_platform_driver_register_all(char *class_str)
+void __init sh_early_platform_driver_register_all(char *class_str)
{
/* The "class_str" parameter may or may not be present on the kernel
* command line. If it is present then there may be more than one
@@ -159,23 +159,23 @@ void __init early_platform_driver_register_all(char *class_str)
* We use parse_early_options() to make sure the early_param() gets
* called at least once. The early_param() may be called more than
* once since the name of the preferred device may be specified on
- * the kernel command line. early_platform_driver_register() handles
+ * the kernel command line. sh_early_platform_driver_register() handles
* this case for us.
*/
parse_early_options(class_str);
}
/**
- * early_platform_match - find early platform device matching driver
+ * sh_early_platform_match - find early platform device matching driver
* @epdrv: early platform driver structure
* @id: id to match against
*/
static struct platform_device * __init
-early_platform_match(struct early_platform_driver *epdrv, int id)
+sh_early_platform_match(struct sh_early_platform_driver *epdrv, int id)
{
struct platform_device *pd;
- list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+ list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
if (pd->id == id)
return pd;
@@ -184,16 +184,16 @@ early_platform_match(struct early_platform_driver *epdrv, int id)
}
/**
- * early_platform_left - check if early platform driver has matching devices
+ * sh_early_platform_left - check if early platform driver has matching devices
* @epdrv: early platform driver structure
* @id: return true if id or above exists
*/
-static int __init early_platform_left(struct early_platform_driver *epdrv,
+static int __init sh_early_platform_left(struct sh_early_platform_driver *epdrv,
int id)
{
struct platform_device *pd;
- list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+ list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
if (pd->id >= id)
return 1;
@@ -202,22 +202,22 @@ static int __init early_platform_left(struct early_platform_driver *epdrv,
}
/**
- * early_platform_driver_probe_id - probe drivers matching class_str and id
+ * sh_early_platform_driver_probe_id - probe drivers matching class_str and id
* @class_str: string to identify early platform driver class
* @id: id to match against
* @nr_probe: number of platform devices to successfully probe before exiting
*/
-static int __init early_platform_driver_probe_id(char *class_str,
+static int __init sh_early_platform_driver_probe_id(char *class_str,
int id,
int nr_probe)
{
- struct early_platform_driver *epdrv;
+ struct sh_early_platform_driver *epdrv;
struct platform_device *match;
int match_id;
int n = 0;
int left = 0;
- list_for_each_entry(epdrv, &early_platform_driver_list, list) {
+ list_for_each_entry(epdrv, &sh_early_platform_driver_list, list) {
/* only use drivers matching our class_str */
if (strcmp(class_str, epdrv->class_str))
continue;
@@ -228,7 +228,7 @@ static int __init early_platform_driver_probe_id(char *class_str,
} else {
match_id = id;
- left += early_platform_left(epdrv, id);
+ left += sh_early_platform_left(epdrv, id);
/* skip requested id */
switch (epdrv->requested_id) {
@@ -250,7 +250,7 @@ static int __init early_platform_driver_probe_id(char *class_str,
match = NULL;
break;
default:
- match = early_platform_match(epdrv, match_id);
+ match = sh_early_platform_match(epdrv, match_id);
}
if (match) {
@@ -292,7 +292,7 @@ static int __init early_platform_driver_probe_id(char *class_str,
}
/**
- * early_platform_driver_probe - probe a class of registered drivers
+ * sh_early_platform_driver_probe - probe a class of registered drivers
* @class_str: string to identify early platform driver class
* @nr_probe: number of platform devices to successfully probe before exiting
* @user_only: only probe user specified early platform devices
@@ -301,7 +301,7 @@ static int __init early_platform_driver_probe_id(char *class_str,
* within a certain class. For probe to happen a registered early platform
* device matching a registered early platform driver is needed.
*/
-int __init early_platform_driver_probe(char *class_str,
+int __init sh_early_platform_driver_probe(char *class_str,
int nr_probe,
int user_only)
{
@@ -309,7 +309,7 @@ int __init early_platform_driver_probe(char *class_str,
n = 0;
for (i = -2; n < nr_probe; i++) {
- k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
+ k = sh_early_platform_driver_probe_id(class_str, i, nr_probe - n);
if (k < 0)
break;
@@ -324,14 +324,14 @@ int __init early_platform_driver_probe(char *class_str,
}
/**
- * early_platform_cleanup - clean up early platform code
+ * sh_early_platform_cleanup - clean up early platform code
*/
-static int __init early_platform_cleanup(void)
+static int __init sh_early_platform_cleanup(void)
{
struct platform_device *pd, *pd2;
/* clean up the devres list used to chain devices */
- list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
+ list_for_each_entry_safe(pd, pd2, &sh_early_platform_device_list,
dev.devres_head) {
list_del(&pd->dev.devres_head);
memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
@@ -343,4 +343,4 @@ static int __init early_platform_cleanup(void)
* This must happen once after all early devices are probed but before probing
* real platform devices.
*/
-subsys_initcall(early_platform_cleanup);
+subsys_initcall(sh_early_platform_cleanup);
diff --git a/arch/sh/include/asm/platform_early.h b/arch/sh/include/asm/platform_early.h
index 4590ab757d5f..fc802137c37d 100644
--- a/arch/sh/include/asm/platform_early.h
+++ b/arch/sh/include/asm/platform_early.h
@@ -8,7 +8,7 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
-struct early_platform_driver {
+struct sh_early_platform_driver {
const char *class_str;
struct platform_driver *pdrv;
struct list_head list;
@@ -20,39 +20,39 @@ struct early_platform_driver {
#define EARLY_PLATFORM_ID_UNSET -2
#define EARLY_PLATFORM_ID_ERROR -3
-extern int early_platform_driver_register(struct early_platform_driver *epdrv,
+extern int sh_early_platform_driver_register(struct sh_early_platform_driver *epdrv,
char *buf);
-extern void early_platform_add_devices(struct platform_device **devs, int num);
+extern void sh_early_platform_add_devices(struct platform_device **devs, int num);
-static inline int is_early_platform_device(struct platform_device *pdev)
+static inline int is_sh_early_platform_device(struct platform_device *pdev)
{
return !pdev->dev.driver;
}
-extern void early_platform_driver_register_all(char *class_str);
-extern int early_platform_driver_probe(char *class_str,
+extern void sh_early_platform_driver_register_all(char *class_str);
+extern int sh_early_platform_driver_probe(char *class_str,
int nr_probe, int user_only);
-#define early_platform_init(class_string, platdrv) \
- early_platform_init_buffer(class_string, platdrv, NULL, 0)
+#define sh_early_platform_init(class_string, platdrv) \
+ sh_early_platform_init_buffer(class_string, platdrv, NULL, 0)
#ifndef MODULE
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static __initdata struct early_platform_driver early_driver = { \
+#define sh_early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
+static __initdata struct sh_early_platform_driver early_driver = { \
.class_str = class_string, \
.buffer = buf, \
.bufsize = bufsiz, \
.pdrv = platdrv, \
.requested_id = EARLY_PLATFORM_ID_UNSET, \
}; \
-static int __init early_platform_driver_setup_func(char *buffer) \
+static int __init sh_early_platform_driver_setup_func(char *buffer) \
{ \
- return early_platform_driver_register(&early_driver, buffer); \
+ return sh_early_platform_driver_register(&early_driver, buffer); \
} \
-early_param(class_string, early_platform_driver_setup_func)
+early_param(class_string, sh_early_platform_driver_setup_func)
#else /* MODULE */
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static inline char *early_platform_driver_setup_func(void) \
+#define sh_early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
+static inline char *sh_early_platform_driver_setup_func(void) \
{ \
return bufsiz ? buf : NULL; \
}
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index a02fc03baef8..6d0425affa71 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -203,6 +203,6 @@ void __init plat_early_device_setup(void)
/* enable CMT clock */
__raw_writeb(__raw_readb(STBCR3) & ~0x10, STBCR3);
- early_platform_add_devices(sh7619_early_devices,
+ sh_early_platform_add_devices(sh7619_early_devices,
ARRAY_SIZE(sh7619_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-mxg.c b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
index d33568a12fad..fb9dd473a9cc 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-mxg.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
@@ -173,6 +173,6 @@ static struct platform_device *mxg_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(mxg_early_devices,
+ sh_early_platform_add_devices(mxg_early_devices,
ARRAY_SIZE(mxg_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
index b258c5c3af60..37357d0fc9bc 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
@@ -416,6 +416,6 @@ void __init plat_early_device_setup(void)
/* enable MTU2 clock */
__raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
- early_platform_add_devices(sh7201_early_devices,
+ sh_early_platform_add_devices(sh7201_early_devices,
ARRAY_SIZE(sh7201_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
index db3f8df8d76d..79ba8d0db6b0 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
@@ -353,6 +353,6 @@ void __init plat_early_device_setup(void)
/* enable MTU2 clock */
__raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
- early_platform_add_devices(sh7203_early_devices,
+ sh_early_platform_add_devices(sh7203_early_devices,
ARRAY_SIZE(sh7203_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index e1be4fedc739..501922504a3f 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -289,6 +289,6 @@ void __init plat_early_device_setup(void)
/* enable MTU2 clock */
__raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
- early_platform_add_devices(sh7206_early_devices,
+ sh_early_platform_add_devices(sh7206_early_devices,
ARRAY_SIZE(sh7206_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7264.c b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
index b5bed10d0d72..955f15386bbd 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
@@ -550,6 +550,6 @@ static struct platform_device *sh7264_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7264_early_devices,
+ sh_early_platform_add_devices(sh7264_early_devices,
ARRAY_SIZE(sh7264_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7269.c b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
index 248a6732397a..d8ecb24a0888 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
@@ -566,6 +566,6 @@ static struct platform_device *sh7269_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7269_early_devices,
+ sh_early_platform_add_devices(sh7269_early_devices,
ARRAY_SIZE(sh7269_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index 7ec8c11c2f7a..481cfbc3b82d 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -182,7 +182,7 @@ static struct platform_device *sh7705_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7705_early_devices,
+ sh_early_platform_add_devices(sh7705_early_devices,
ARRAY_SIZE(sh7705_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
index 20839dd40a2f..d0cd14f5fc19 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
@@ -234,7 +234,7 @@ static struct platform_device *sh770x_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh770x_early_devices,
+ sh_early_platform_add_devices(sh770x_early_devices,
ARRAY_SIZE(sh770x_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 780ccd202bab..fb680bae22c3 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -181,7 +181,7 @@ static struct platform_device *sh7710_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7710_early_devices,
+ sh_early_platform_add_devices(sh7710_early_devices,
ARRAY_SIZE(sh7710_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
index 723bd9c04c8a..faf084cbbbed 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
@@ -215,7 +215,7 @@ static struct platform_device *sh7720_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7720_early_devices,
+ sh_early_platform_add_devices(sh7720_early_devices,
ARRAY_SIZE(sh7720_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
index 4a5fa86006cd..123b848368d4 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -80,7 +80,7 @@ static struct platform_device *sh4202_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh4202_early_devices,
+ sh_early_platform_add_devices(sh4202_early_devices,
ARRAY_SIZE(sh4202_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index abb3703c2273..8f6c83b745db 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -165,15 +165,15 @@ void __init plat_early_device_setup(void)
if (mach_is_rts7751r2d()) {
scif_platform_data.scscr |= SCSCR_CKE1;
dev[0] = &scif_device;
- early_platform_add_devices(dev, 1);
+ sh_early_platform_add_devices(dev, 1);
} else {
dev[0] = &sci_device;
- early_platform_add_devices(dev, 1);
+ sh_early_platform_add_devices(dev, 1);
dev[0] = &scif_device;
- early_platform_add_devices(dev, 1);
+ sh_early_platform_add_devices(dev, 1);
}
- early_platform_add_devices(sh7750_early_devices,
+ sh_early_platform_add_devices(sh7750_early_devices,
ARRAY_SIZE(sh7750_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index 649f4dcb5935..ab8cc1826d8c 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -275,7 +275,7 @@ static struct platform_device *sh7760_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7760_early_devices,
+ sh_early_platform_add_devices(sh7760_early_devices,
ARRAY_SIZE(sh7760_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 73715a635048..a3ff0803b62e 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
@@ -300,7 +300,7 @@ static struct platform_device *sh7343_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7343_early_devices,
+ sh_early_platform_add_devices(sh7343_early_devices,
ARRAY_SIZE(sh7343_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
index 942856048112..2ad400fef830 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
@@ -244,7 +244,7 @@ static struct platform_device *sh7366_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7366_early_devices,
+ sh_early_platform_add_devices(sh7366_early_devices,
ARRAY_SIZE(sh7366_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index bf60456a8012..01e687d72c16 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -516,7 +516,7 @@ static struct platform_device *sh7722_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7722_early_devices,
+ sh_early_platform_add_devices(sh7722_early_devices,
ARRAY_SIZE(sh7722_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
index d25d3c3b44ab..6738c39413b2 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
@@ -414,7 +414,7 @@ static struct platform_device *sh7723_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7723_early_devices,
+ sh_early_platform_add_devices(sh7723_early_devices,
ARRAY_SIZE(sh7723_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index 0eeadabc8065..0163750a3fb0 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -834,7 +834,7 @@ static struct platform_device *sh7724_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7724_early_devices,
+ sh_early_platform_add_devices(sh7724_early_devices,
ARRAY_SIZE(sh7724_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
index bed9d01fa85f..d3760029f0f3 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
@@ -284,7 +284,7 @@ static struct platform_device *sh7734_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7734_early_devices,
+ sh_early_platform_add_devices(sh7734_early_devices,
ARRAY_SIZE(sh7734_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index b5b19e81a8dc..25d655ab4114 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -771,7 +771,7 @@ static struct platform_device *sh7757_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7757_early_devices,
+ sh_early_platform_add_devices(sh7757_early_devices,
ARRAY_SIZE(sh7757_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
index 51a6c64f860e..42f234efaa42 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
@@ -225,7 +225,7 @@ static struct platform_device *sh7763_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7763_early_devices,
+ sh_early_platform_add_devices(sh7763_early_devices,
ARRAY_SIZE(sh7763_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
index 77f228e20599..35420329f5e1 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
@@ -320,7 +320,7 @@ static struct platform_device *sh7770_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7770_early_devices,
+ sh_early_platform_add_devices(sh7770_early_devices,
ARRAY_SIZE(sh7770_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index c4cbb7584122..3a75db564c24 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -289,7 +289,7 @@ void __init plat_early_device_setup(void)
scif1_platform_data.scscr &= ~SCSCR_CKE1;
}
- early_platform_add_devices(sh7780_early_devices,
+ sh_early_platform_add_devices(sh7780_early_devices,
ARRAY_SIZE(sh7780_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index eda0d61ebf71..eb3c003223e2 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -357,7 +357,7 @@ static struct platform_device *sh7785_early_devices[] __initdata = {
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7785_early_devices,
+ sh_early_platform_add_devices(sh7785_early_devices,
ARRAY_SIZE(sh7785_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
index 77226a60c36f..46473345cb79 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
@@ -838,6 +838,6 @@ arch_initcall(sh7786_devices_setup);
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh7786_early_devices,
+ sh_early_platform_add_devices(sh7786_early_devices,
ARRAY_SIZE(sh7786_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index 83feaf0a4aae..c531182425f7 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -156,7 +156,7 @@ arch_initcall(shx3_devices_setup);
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(shx3_early_devices,
+ sh_early_platform_add_devices(shx3_early_devices,
ARRAY_SIZE(shx3_early_devices));
}
diff --git a/arch/sh/kernel/cpu/sh5/setup-sh5.c b/arch/sh/kernel/cpu/sh5/setup-sh5.c
index 8ebd26a9fd90..034bb36bfdc2 100644
--- a/arch/sh/kernel/cpu/sh5/setup-sh5.c
+++ b/arch/sh/kernel/cpu/sh5/setup-sh5.c
@@ -119,6 +119,6 @@ arch_initcall(sh5_devices_setup);
void __init plat_early_device_setup(void)
{
- early_platform_add_devices(sh5_early_devices,
+ sh_early_platform_add_devices(sh5_early_devices,
ARRAY_SIZE(sh5_early_devices));
}
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index aed8f331f66b..74548fc31a3d 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -328,7 +328,7 @@ void __init setup_arch(char **cmdline_p)
sh_mv_setup();
/* Let earlyprintk output early console messages */
- early_platform_driver_probe("earlyprintk", 1, 1);
+ sh_early_platform_driver_probe("earlyprintk", 1, 1);
#ifdef CONFIG_OF_FLATTREE
#ifdef CONFIG_USE_BUILTIN_DTB
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index 674d8413491b..9c460a74e3c2 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -105,8 +105,8 @@ static void __init sh_late_time_init(void)
* clocksource and the jiffies clocksource is used transparently
* instead. No error handling is necessary here.
*/
- early_platform_driver_register_all("earlytimer");
- early_platform_driver_probe("earlytimer", 2, 0);
+ sh_early_platform_driver_register_all("earlytimer");
+ sh_early_platform_driver_probe("earlytimer", 2, 0);
}
void __init time_init(void)
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index fe9abe5b3e68..49f36c26e6fb 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -1047,7 +1047,7 @@ static int sh_cmt_probe(struct platform_device *pdev)
struct sh_cmt_device *cmt = platform_get_drvdata(pdev);
int ret;
- if (!is_early_platform_device(pdev)) {
+ if (!is_sh_early_platform_device(pdev)) {
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
@@ -1067,7 +1067,7 @@ static int sh_cmt_probe(struct platform_device *pdev)
pm_runtime_idle(&pdev->dev);
return ret;
}
- if (is_early_platform_device(pdev))
+ if (is_sh_early_platform_device(pdev))
return 0;
out:
@@ -1105,7 +1105,7 @@ static void __exit sh_cmt_exit(void)
}
#ifdef CONFIG_SUPERH
-early_platform_init("earlytimer", &sh_cmt_device_driver);
+sh_early_platform_init("earlytimer", &sh_cmt_device_driver);
#endif
subsys_initcall(sh_cmt_init);
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index becff3a1a6fb..05120ef24833 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -454,7 +454,7 @@ static int sh_mtu2_probe(struct platform_device *pdev)
struct sh_mtu2_device *mtu = platform_get_drvdata(pdev);
int ret;
- if (!is_early_platform_device(pdev)) {
+ if (!is_sh_early_platform_device(pdev)) {
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
@@ -474,7 +474,7 @@ static int sh_mtu2_probe(struct platform_device *pdev)
pm_runtime_idle(&pdev->dev);
return ret;
}
- if (is_early_platform_device(pdev))
+ if (is_sh_early_platform_device(pdev))
return 0;
out:
@@ -524,7 +524,7 @@ static void __exit sh_mtu2_exit(void)
}
#ifdef CONFIG_SUPERH
-early_platform_init("earlytimer", &sh_mtu2_device_driver);
+sh_early_platform_init("earlytimer", &sh_mtu2_device_driver);
#endif
subsys_initcall(sh_mtu2_init);
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index 3f4783a9ecf0..6f2c5279c1fd 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -610,7 +610,7 @@ static int sh_tmu_probe(struct platform_device *pdev)
struct sh_tmu_device *tmu = platform_get_drvdata(pdev);
int ret;
- if (!is_early_platform_device(pdev)) {
+ if (!is_sh_early_platform_device(pdev)) {
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
@@ -631,7 +631,7 @@ static int sh_tmu_probe(struct platform_device *pdev)
return ret;
}
- if (is_early_platform_device(pdev))
+ if (is_sh_early_platform_device(pdev))
return 0;
out:
@@ -682,7 +682,7 @@ static void __exit sh_tmu_exit(void)
}
#ifdef CONFIG_SUPERH
-early_platform_init("earlytimer", &sh_tmu_device_driver);
+sh_early_platform_init("earlytimer", &sh_tmu_device_driver);
#endif
subsys_initcall(sh_tmu_init);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index a6c3aa7a7de8..1d2e645f35d5 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -3220,7 +3220,7 @@ static int sci_probe(struct platform_device *dev)
* to make it beyond this yet.
*/
#ifdef CONFIG_SUPERH
- if (is_early_platform_device(dev))
+ if (is_sh_early_platform_device(dev))
return sci_probe_earlyprintk(dev);
#endif
@@ -3320,7 +3320,7 @@ static void __exit sci_exit(void)
}
#if defined(CONFIG_SUPERH) && defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
-early_platform_init_buffer("earlyprintk", &sci_driver,
+sh_early_platform_init_buffer("earlyprintk", &sci_driver,
early_serial_buf, ARRAY_SIZE(early_serial_buf));
#endif
#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 7d7610da8377..a03d5cd7dc5a 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -324,7 +324,7 @@ extern int platform_dma_configure(struct device *dev);
* drivers. It should go away once we introduce the new platform_device-based
* early driver framework.
*/
-static inline int is_early_platform_device(struct platform_device *pdev)
+static inline int is_sh_early_platform_device(struct platform_device *pdev)
{
return 0;
}
--
2.17.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox