* [RFC PATCH v2 4/8] arm64: compat: Add a 32-bit vDSO
From: Kevin Brodsky @ 2016-12-01 14:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161121184414.GC28723@e104818-lin.cambridge.arm.com>
On 21/11/16 18:44, Catalin Marinas wrote:
> On Mon, Nov 21, 2016 at 03:45:55PM +0000, Kevin Brodsky wrote:
>> On 04/11/16 20:03, Catalin Marinas wrote:
>>> On Fri, Oct 28, 2016 at 11:20:07AM +0100, Kevin Brodsky wrote:
>>>> On 28/10/16 04:09, Jisheng Zhang wrote:
>>>>> On Thu, 27 Oct 2016 17:30:54 +0100 Kevin Brodsky wrote:
>>>>>> +# Force -O2 to avoid libgcc dependencies
>>>>>> +VDSO_CFLAGS := -march=armv8-a -O2
>>>>> For completeness, bringing 32bit compiler need to check whether the 32bit
>>>>> toolchain support some options. IIRC, armv8-a support isn't enabled until
>>>>> gcc 4.8, so old toolchains such gcc-4.7 will complain:
>>>>> error: unrecognized argument in option ?-march=armv8-a?
>>>> That's a fair point. I guess -march=armv8-a is not strictly necessary and
>>>> the produced vDSO should be fine if arch/arm/vdso also compiles fine.
>>>> However we would still need to pass -march=armv7-a. I'm not sure what to do
>>>> between:
>>>> * Checking that the compiler supports -march=armv8-a when inspecting
>>>> CROSS_COMPILE_ARM32, and if it doesn't vdso32 will not be built.
>>>> * Checking whether -march=armv8-a is available here, and if it is not fall
>>>> back to -march=armv7-a.
>>> Does v8 vs v7 make any difference in the generated code? If not, we
>>> could just stick to armv7-a permanently.
>> I've just tried compiling with -march=armv7-a, and in fact it doesn't
>> compile at all. It turns out vgettimeofday.c uses smp_rmb(), which expands
>> to dmb ishld on arm64, and ishld doesn't exist in ARMv7. We could possibly
>> work around that, but I think requiring GCC 4.8 is reasonable.
> Since vgettimeofday.c is meant to be compiled for AArch32, it wouldn't
> look too bad to define its own barriers rather than relying on the
> AArch64 ones. So you could define v7_smp_rmb/v7_smp_wmb and use them in
> this file. Alternatively, replace smp_rmb() with smp_mb() in this file
> but with a big comment about ARMv7 compilation requirement and "ishld"
> not being available.
Fair enough. I'll add AArch32 barrier macros and compile with -march=armv7-a if the
compiler doesn't support armv8-a. It's true that using arm64 barrier macros in 32-bit
code is a bit dodgy anyway.
Cheers,
Kevin
^ permalink raw reply
* [PATCH v2] USB: OHCI: ohci-s3c2410: remove useless functions
From: csmanjuvijay at gmail.com @ 2016-12-01 14:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480542166-7032-1-git-send-email-csmanjuvijay@gmail.com>
From: Manjunath Goudar <csmanjuvijay@gmail.com>
The ohci_hcd_s3c2410_drv_probe and ohci_hcd_s3c2410_drv_remove
functions are removed as these are useless functions except calling
usb_hcd_s3c2410_probe and usb_hcd_s3c2410_remove functions.
The usb_hcd_s3c2410_probe function renamed to ohci_hcd_s3c2410_drv_probe
and usb_hcd_s3c2410_remove function renamed to ohci_hcd_s3c2410_drv_remove
for proper naming.
Signed-off-by: Manjunath Goudar <csmanjuvijay@gmail.com>
Cc: Kukjin Kim <kgene@kernel.org>
Cc: Krzysztof Kozlowski <krzk@kernel.org>
Cc: Javier Martinez Canillas <javier@osg.samsung.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-samsung-soc at vger.kernel.org
Cc: linux-usb at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
---
Changelog v1 -> v2:
Removed checkpatch.pl warnings and errors cleanup code which is not related
to this patch.
drivers/usb/host/ohci-s3c2410.c | 39 ++++++++++++++-------------------------
1 file changed, 14 insertions(+), 25 deletions(-)
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index d8e03a8..b006b93 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -43,6 +43,8 @@ static const char hcd_name[] = "ohci-s3c2410";
static struct clk *clk;
static struct clk *usb_clk;
+static struct hc_driver __read_mostly ohci_s3c2410_hc_driver;
+
/* forward definitions */
static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc);
@@ -321,26 +323,29 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
/* may be called with controller, bus, and devices active */
/*
- * usb_hcd_s3c2410_remove - shutdown processing for HCD
+ * ohci_hcd_s3c2410_remove - shutdown processing for HCD
* @dev: USB Host Controller being removed
* Context: !in_interrupt()
*
- * Reverses the effect of usb_hcd_3c2410_probe(), first invoking
+ * Reverses the effect of ohci_hcd_3c2410_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
*
*/
-static void
-usb_hcd_s3c2410_remove(struct usb_hcd *hcd, struct platform_device *dev)
+static int
+ohci_hcd_s3c2410_remove(struct platform_device *dev)
{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
usb_remove_hcd(hcd);
s3c2410_stop_hc(dev);
usb_put_hcd(hcd);
+ return 0;
}
/**
- * usb_hcd_s3c2410_probe - initialize S3C2410-based HCDs
+ * ohci_hcd_s3c2410_probe - initialize S3C2410-based HCDs
* Context: !in_interrupt()
*
* Allocates basic resources for this USB host controller, and
@@ -348,8 +353,7 @@ usb_hcd_s3c2410_remove(struct usb_hcd *hcd, struct platform_device *dev)
* through the hotplug entry's driver_data.
*
*/
-static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
- struct platform_device *dev)
+static int ohci_hcd_s3c2410_probe(struct platform_device *dev)
{
struct usb_hcd *hcd = NULL;
struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
@@ -358,7 +362,7 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
s3c2410_usb_set_power(info, 1, 1);
s3c2410_usb_set_power(info, 2, 1);
- hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
+ hcd = usb_create_hcd(&ohci_s3c2410_hc_driver, &dev->dev, "s3c24xx");
if (hcd == NULL)
return -ENOMEM;
@@ -404,21 +408,6 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
/*-------------------------------------------------------------------------*/
-static struct hc_driver __read_mostly ohci_s3c2410_hc_driver;
-
-static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)
-{
- return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev);
-}
-
-static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- usb_hcd_s3c2410_remove(hcd, pdev);
- return 0;
-}
-
#ifdef CONFIG_PM
static int ohci_hcd_s3c2410_drv_suspend(struct device *dev)
{
@@ -465,8 +454,8 @@ static const struct of_device_id ohci_hcd_s3c2410_dt_ids[] = {
MODULE_DEVICE_TABLE(of, ohci_hcd_s3c2410_dt_ids);
static struct platform_driver ohci_hcd_s3c2410_driver = {
- .probe = ohci_hcd_s3c2410_drv_probe,
- .remove = ohci_hcd_s3c2410_drv_remove,
+ .probe = ohci_hcd_s3c2410_probe,
+ .remove = ohci_hcd_s3c2410_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "s3c2410-ohci",
--
2.7.4
^ permalink raw reply related
* [PATCH 0/4] ARM, arm64: dts: Use usb-phy fallback bindings
From: Geert Uytterhoeven @ 2016-12-01 14:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480602354-1446-1-git-send-email-horms+renesas@verge.net.au>
On Thu, Dec 1, 2016 at 3:25 PM, Simon Horman <horms+renesas@verge.net.au> wrote:
> this short series makes use of fallback bindings for Renesas R-Car PHY
> drivers in the DT of SoCs which already use those drivers.
>
> Simon Horman (4):
> ARM: dts: r8a7790: Use renesas,rcar-gen2-usb-phy fallback binding
> ARM: dts: r8a7791: Use renesas,rcar-gen2-usb-phy fallback binding
> ARM: dts: r8a7794: Use renesas,rcar-gen2-usb-phy fallback binding
> arm64: dts: r8a7795: Use renesas,rcar-gen3-usb2-phy fallback binding
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH V1 1/2] PCI: thunder: Enable ACPI PCI controller for ThunderX pass2.x silicon version
From: Lorenzo Pieralisi @ 2016-12-01 14:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161201135549.GP2213@rric.localdomain>
On Thu, Dec 01, 2016 at 02:55:49PM +0100, Robert Richter wrote:
> Tomasz, Bjorn,
>
> On 01.12.16 09:49:51, Tomasz Nowicki wrote:
> > I put the picture together here (on top of your pci/ecam branch):
> > [1] https://github.com/semihalf-nowicki-tomasz/linux/commits/pci-quirks-thunderx-v2
>
> please note that acpi_* functions must be protected with acpi_disabled
> or something else to make sure an acpi enabled kernel does not break
> dt. See the crash below with above branch.
You could use struct device.of_node, or just move the MCFG check to ACPI
code that probes the root bus in arm64 before calling pci_ecam_create()
which will save you some ifdeffery too while at it.
Lorenzo
> -Robert
>
> [ 12.493028] Unable to handle kernel NULL pointer dereference at virtual address 00000018
> [ 12.501113] pgd = ffff0000090a0000
> [ 12.504511] [00000018] *pgd=0000010fffef0003[ 12.508602] , *pud=0000010fffef0003
> , *pmd=0000010fffee0003[ 12.514093] , *pte=0000000000000000
> [ 12.517575]
> [ 12.519064] Internal error: Oops: 96000005 [#1] SMP
> [ 12.523933] Modules linked in:
> [ 12.526987] CPU: 73 PID: 1 Comm: swapper/0 Tainted: G W 4.9.0-rc6.0.vanilla10-00019-g09abd2b6bbeb #135
> [ 12.537409] Hardware name: Cavium ThunderX CRB/To be filled by O.E.M., BIOS 5.11 12/12/2012
> [ 12.545748] task: ffff800fe85b8000 task.stack: ffff800ff4288000
> [ 12.551674] PC is at acpi_ns_walk_namespace+0x68/0x1d4
> [ 12.556803] LR is at acpi_get_devices+0x6c/0x94
> ...
> [ 13.124920] [<ffff0000084dc5a0>] acpi_ns_walk_namespace+0x68/0x1d4
> [ 13.131090] [<ffff0000084dcadc>] acpi_get_devices+0x6c/0x94
> [ 13.136663] [<ffff0000084c0aec>] acpi_resource_consumer+0x34/0x44
> [ 13.142752] [<ffff000008496bc0>] pci_ecam_create+0x80/0x228
> [ 13.148314] [<ffff000008498e64>] pci_host_common_probe+0x294/0x348
> [ 13.154486] [<ffff00000849bf3c>] thunder_ecam_probe+0x2c/0x38
> [ 13.160226] [<ffff0000085880b8>] platform_drv_probe+0x60/0xc8
> [ 13.165970] [<ffff000008585a04>] driver_probe_device+0x26c/0x420
> [ 13.171966] [<ffff000008585cdc>] __driver_attach+0x124/0x128
> [ 13.177615] [<ffff000008583238>] bus_for_each_dev+0x70/0xb0
> [ 13.183177] [<ffff000008585060>] driver_attach+0x30/0x40
> [ 13.188478] [<ffff000008584a98>] bus_add_driver+0x200/0x2b8
> [ 13.194041] [<ffff000008586860>] driver_register+0x68/0x100
> [ 13.199602] [<ffff000008587fdc>] __platform_driver_register+0x54/0x60
> [ 13.206038] [<ffff000008c39b98>] thunder_ecam_driver_init+0x18/0x20
> [ 13.212296] [<ffff000008082d94>] do_one_initcall+0x44/0x138
> [ 13.217862] [<ffff000008c00d0c>] kernel_init_freeable+0x1ac/0x24c
> [ 13.223950] [<ffff0000088605f0>] kernel_init+0x18/0x110
> [ 13.229165] [<ffff000008082b30>] ret_from_fork+0x10/0x20
^ permalink raw reply
* [PATCH v2] ARM: davinci: da8xx: Fix sleeping function called from invalid context
From: Arnd Bergmann @ 2016-12-01 14:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <ed09fc5e-395a-5e72-4928-5e85cdc7f2c3@ti.com>
On Thursday, December 1, 2016 7:47:12 PM CET Sekhar Nori wrote:
>
> > @@ -287,9 +281,15 @@ int __init da8xx_register_usb20_phy_clk(bool use_usb_refclkin)
> > struct clk *parent;
> > int ret = 0;
> >
> > + usb20_clk = clk_get(&da8xx_usb20_dev.dev, "usb20");
> > + if (IS_ERR(usb20_clk))
> > + return PTR_ERR(parent);
>
> Typo here. Should be PTR_ERR(usb20_clk)
I found that doing
err = PTR_ERR_OR_ZERO(usb20_clk);
if (err)
return err;
is less error-prone and leads to better object code.
Arnd
^ permalink raw reply
* [PATCH/RFC] ARM64: use this_cpu_read in raw_smp_processor_id()
From: Marek Szyprowski @ 2016-12-01 15:00 UTC (permalink / raw)
To: linux-arm-kernel
Direct access to cpu_number entry in per-cpu variables causes boot
failure on Exynos5433, so replace it with this_cpu_read() macro.
This approach is also used on x86_64.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
This change is needed to get linux-next to boot on Exynos5433, otherwise it
hangs somewhere in early init. There is even no message on the earlycon.
This issue appeared first on linux-next from 14.11.2016. The tree from
11.11.2016 is the last one, which boots on Exynos5433. I've tried to
debug a bit this issue, but I ran out of ideas.
Any comments or suggestions are welcome.
Best regards
Marek Szyprowski
Samsung R&D Institute Poland
---
arch/arm64/include/asm/smp.h | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index a62db952ffcb..d514383d6219 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -37,12 +37,7 @@
DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
-/*
- * We don't use this_cpu_read(cpu_number) as that has implicit writes to
- * preempt_count, and associated (compiler) barriers, that we'd like to avoid
- * the expense of. If we're preemptible, the value can be stale at use anyway.
- */
-#define raw_smp_processor_id() (*this_cpu_ptr(&cpu_number))
+#define raw_smp_processor_id() (this_cpu_read(cpu_number))
struct seq_file;
--
1.9.1
^ permalink raw reply related
* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Mark Salter @ 2016-12-01 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480549373-2123-1-git-send-email-dhdang@apm.com>
On Wed, 2016-11-30 at 15:42 -0800, Duc Dang wrote:
> PCIe controllers in X-Gene SoCs is not ECAM compliant: software
> needs to configure additional controller's register to address
> device at bus:dev:function.
>
> The quirk will only be applied for X-Gene PCIe MCFG table with
> OEM revison 1, 2, 3 or 4 (PCIe controller v1 and v2 on X-Gene SoCs).
>
> The quirk declares the X-Gene PCIe controller register space as 64KB
> fixed memory resource with name "PCIe CSR". This name will be showed
> next to the resource range in the output of "cat /proc/iomem".
>
> Signed-off-by: Duc Dang <dhdang@apm.com>
> ---
> v3:
> ? - Rebase on top of pci/ecam-v6 tree.
> ? - Use DEFINE_RES_MEM_NAMED to declare controller register space
> ? with name "PCIe CSR"
> v2:
> ? RFC v2: https://patchwork.ozlabs.org/patch/686846/
> v1:
> ? RFC v1: https://patchwork.kernel.org/patch/9337115/
>
> ?drivers/acpi/pci_mcfg.c??????|??31 ++++++++
> ?drivers/pci/host/pci-xgene.c | 165 ++++++++++++++++++++++++++++++++++++++++++-
> ?include/linux/pci-ecam.h?????|???7 ++
> ?3 files changed, 200 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
> index ac21db3..eb6125b 100644
> --- a/drivers/acpi/pci_mcfg.c
> +++ b/drivers/acpi/pci_mcfg.c
> @@ -57,6 +57,37 @@ struct mcfg_fixup {
> ? { "QCOM??", "QDF2432 ", 1, 5, MCFG_BUS_ANY, &pci_32b_ops },
> ? { "QCOM??", "QDF2432 ", 1, 6, MCFG_BUS_ANY, &pci_32b_ops },
> ? { "QCOM??", "QDF2432 ", 1, 7, MCFG_BUS_ANY, &pci_32b_ops },
> +
> +#ifdef CONFIG_PCI_XGENE
> +#define XGENE_V1_ECAM_MCFG(rev, seg) \
> + {"APM???", "XGENE???", rev, seg, MCFG_BUS_ANY, \
> + &xgene_v1_pcie_ecam_ops }
> +#define XGENE_V2_1_ECAM_MCFG(rev, seg) \
> + {"APM???", "XGENE???", rev, seg, MCFG_BUS_ANY, \
> + &xgene_v2_1_pcie_ecam_ops }
> +#define XGENE_V2_2_ECAM_MCFG(rev, seg) \
> + {"APM???", "XGENE???", rev, seg, MCFG_BUS_ANY, \
> + &xgene_v2_2_pcie_ecam_ops }
> +
> + /* X-Gene SoC with v1 PCIe controller */
> + XGENE_V1_ECAM_MCFG(1, 0),
> + XGENE_V1_ECAM_MCFG(1, 1),
> + XGENE_V1_ECAM_MCFG(1, 2),
> + XGENE_V1_ECAM_MCFG(1, 3),
> + XGENE_V1_ECAM_MCFG(1, 4),
> + XGENE_V1_ECAM_MCFG(2, 0),
> + XGENE_V1_ECAM_MCFG(2, 1),
> + XGENE_V1_ECAM_MCFG(2, 2),
> + XGENE_V1_ECAM_MCFG(2, 3),
> + XGENE_V1_ECAM_MCFG(2, 4),
> + /* X-Gene SoC with v2.1 PCIe controller */
> + XGENE_V2_1_ECAM_MCFG(3, 0),
> + XGENE_V2_1_ECAM_MCFG(3, 1),
> + /* X-Gene SoC with v2.2 PCIe controller */
> + XGENE_V2_2_ECAM_MCFG(4, 0),
> + XGENE_V2_2_ECAM_MCFG(4, 1),
> + XGENE_V2_2_ECAM_MCFG(4, 2),
> +#endif
> ?};
> ?
> ?static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
> diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
> index 1de23d7..43d7c69 100644
> --- a/drivers/pci/host/pci-xgene.c
> +++ b/drivers/pci/host/pci-xgene.c
> @@ -27,6 +27,8 @@
> ?#include <linux/of_irq.h>
> ?#include <linux/of_pci.h>
> ?#include <linux/pci.h>
> +#include <linux/pci-acpi.h>
> +#include <linux/pci-ecam.h>
> ?#include <linux/platform_device.h>
> ?#include <linux/slab.h>
> ?
> @@ -64,6 +66,7 @@
> ?/* PCIe IP version */
> ?#define XGENE_PCIE_IP_VER_UNKN 0
> ?#define XGENE_PCIE_IP_VER_1 1
> +#define XGENE_PCIE_IP_VER_2 2
> ?
> ?struct xgene_pcie_port {
> ? struct device_node *node;
> @@ -97,7 +100,15 @@ static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
> ? */
> ?static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
> ?{
> - struct xgene_pcie_port *port = bus->sysdata;
> + struct pci_config_window *cfg;
> + struct xgene_pcie_port *port;
> +
> + if (acpi_disabled)
> + port = bus->sysdata;
> + else {
> + cfg = bus->sysdata;
> + port = cfg->priv;
> + }
> ?
> ? if (bus->number >= (bus->primary + 1))
> ? return port->cfg_base + AXI_EP_CFG_ACCESS;
> @@ -111,10 +122,18 @@ static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
> ? */
> ?static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn)
> ?{
> - struct xgene_pcie_port *port = bus->sysdata;
> + struct pci_config_window *cfg;
> + struct xgene_pcie_port *port;
> ? unsigned int b, d, f;
> ? u32 rtdid_val = 0;
> ?
> + if (acpi_disabled)
> + port = bus->sysdata;
> + else {
> + cfg = bus->sysdata;
> + port = cfg->priv;
> + }
> +
> ? b = bus->number;
> ? d = PCI_SLOT(devfn);
> ? f = PCI_FUNC(devfn);
> @@ -158,7 +177,15 @@ static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
> ?static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
> ? ????int where, int size, u32 *val)
> ?{
> - struct xgene_pcie_port *port = bus->sysdata;
> + struct pci_config_window *cfg;
> + struct xgene_pcie_port *port;
> +
> + if (acpi_disabled)
> + port = bus->sysdata;
> + else {
> + cfg = bus->sysdata;
> + port = cfg->priv;
> + }
> ?
> ? if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) !=
> ? ????PCIBIOS_SUCCESSFUL)
> @@ -189,6 +216,138 @@ static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
> ? .write = pci_generic_config_write32,
> ?};
> ?
> +#ifdef CONFIG_ACPI
> +static struct resource xgene_v1_csr_res[] = {
> + [0] = DEFINE_RES_MEM_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"),
> + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"),
> + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"),
> + [3] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"),
> + [4] = DEFINE_RES_MEM_NAMED(0x1f510000UL, SZ_64K, "PCIe CSR"),
> +};
> +
> +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
> +{
> + struct acpi_device *adev = to_acpi_device(cfg->parent);
> + struct acpi_pci_root *root = acpi_driver_data(adev);
> + struct device *dev = cfg->parent;
> + struct xgene_pcie_port *port;
> + struct resource *csr;
> +
> + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> + if (!port)
> + return -ENOMEM;
> +
> + csr = &xgene_v1_csr_res[root->segment];
This hard-coded assumption that segment N uses controller N breaks
for m400 where segment 0 is using controller 3.
> + port->csr_base = devm_ioremap_resource(dev, csr);
> + if (IS_ERR(port->csr_base)) {
> + kfree(port);
> + return -ENOMEM;
> + }
> +
> + port->cfg_base = cfg->win;
> + port->version = XGENE_PCIE_IP_VER_1;
> +
> + cfg->priv = port;
> +
> + return 0;
> +}
> +
> +struct pci_ecam_ops xgene_v1_pcie_ecam_ops = {
> + .bus_shift??????= 16,
> + .init???????????= xgene_v1_pcie_ecam_init,
> + .pci_ops????????= {
> + .map_bus????????= xgene_pcie_map_bus,
> + .read???????????= xgene_pcie_config_read32,
> + .write??????????= pci_generic_config_write,
> + }
> +};
> +
> +static struct resource xgene_v2_1_csr_res[] = {
> + [0] = DEFINE_RES_MEM_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"),
> + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"),
> +};
> +
> +static int xgene_v2_1_pcie_ecam_init(struct pci_config_window *cfg)
> +{
> + struct acpi_device *adev = to_acpi_device(cfg->parent);
> + struct acpi_pci_root *root = acpi_driver_data(adev);
> + struct device *dev = cfg->parent;
> + struct xgene_pcie_port *port;
> + struct resource *csr;
> +
> + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> + if (!port)
> + return -ENOMEM;
> +
> + csr = &xgene_v2_1_csr_res[root->segment];
> + port->csr_base = devm_ioremap_resource(dev, csr);
> + if (IS_ERR(port->csr_base)) {
> + kfree(port);
> + return -ENOMEM;
> + }
> +
> + port->cfg_base = cfg->win;
> + port->version = XGENE_PCIE_IP_VER_2;
> +
> + cfg->priv = port;
> +
> + return 0;
> +}
> +
> +struct pci_ecam_ops xgene_v2_1_pcie_ecam_ops = {
> + .bus_shift??????= 16,
> + .init???????????= xgene_v2_1_pcie_ecam_init,
> + .pci_ops????????= {
> + .map_bus????????= xgene_pcie_map_bus,
> + .read???????????= xgene_pcie_config_read32,
> + .write??????????= pci_generic_config_write,
> + }
> +};
> +
> +static struct resource xgene_v2_2_csr_res[] = {
> + [0] = DEFINE_RES_MEM_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"),
> + [1] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"),
> + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"),
> +};
> +
> +static int xgene_v2_2_pcie_ecam_init(struct pci_config_window *cfg)
> +{
> + struct acpi_device *adev = to_acpi_device(cfg->parent);
> + struct acpi_pci_root *root = acpi_driver_data(adev);
> + struct device *dev = cfg->parent;
> + struct xgene_pcie_port *port;
> + struct resource *csr;
> +
> + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> + if (!port)
> + return -ENOMEM;
> +
> + csr = &xgene_v2_2_csr_res[root->segment];
> + port->csr_base = devm_ioremap_resource(dev, csr);
> + if (IS_ERR(port->csr_base)) {
> + kfree(port);
> + return -ENOMEM;
> + }
> +
> + port->cfg_base = cfg->win;
> + port->version = XGENE_PCIE_IP_VER_2;
> +
> + cfg->priv = port;
> +
> + return 0;
> +}
> +
> +struct pci_ecam_ops xgene_v2_2_pcie_ecam_ops = {
> + .bus_shift??????= 16,
> + .init???????????= xgene_v2_2_pcie_ecam_init,
> + .pci_ops????????= {
> + .map_bus????????= xgene_pcie_map_bus,
> + .read???????????= xgene_pcie_config_read32,
> + .write??????????= pci_generic_config_write,
> + }
> +};
> +#endif
> +
> ?static u64 xgene_pcie_set_ib_mask(struct xgene_pcie_port *port, u32 addr,
> ? ??u32 flags, u64 size)
> ?{
> diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
> index f5740b7..47ab947 100644
> --- a/include/linux/pci-ecam.h
> +++ b/include/linux/pci-ecam.h
> @@ -62,6 +62,13 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
> ?/* ops for buggy ECAM that supports only 32-bit accesses */
> ?extern struct pci_ecam_ops pci_32b_ops;
> ?
> +/* ECAM ops for known quirks */
> +#ifdef CONFIG_PCI_XGENE
> +extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops;
> +extern struct pci_ecam_ops xgene_v2_1_pcie_ecam_ops;
> +extern struct pci_ecam_ops xgene_v2_2_pcie_ecam_ops;
> +#endif
> +
> ?#ifdef CONFIG_PCI_HOST_GENERIC
> ?/* for DT-based PCI controllers that support ECAM */
> ?int pci_host_common_probe(struct platform_device *pdev,
^ permalink raw reply
* [PATCH] ARM: dts: orion5x: fix number of sata port for linkstation ls-gl
From: Roger Shimizu @ 2016-12-01 15:11 UTC (permalink / raw)
To: linux-arm-kernel
Bug report from Debian [0] shows there's minor changed model of
Linkstation LS-GL that uses the 2nd SATA port of the SoC.
So it's necessary to enable two SATA ports, though for that specific
model only the 2nd one is used.
[0] https://bugs.debian.org/845611
Fixes: b1742ffa9ddb ("ARM: dts: orion5x: add device tree for buffalo linkstation ls-gl")
Reported-by: Ryan Tandy <ryan@nardis.ca>
Tested-by: Ryan Tandy <ryan@nardis.ca>
Signed-off-by: Roger Shimizu <rogershimizu@gmail.com>
---
arch/arm/boot/dts/orion5x-linkstation-lsgl.dts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/orion5x-linkstation-lsgl.dts b/arch/arm/boot/dts/orion5x-linkstation-lsgl.dts
index 1cf644b..51dc734 100644
--- a/arch/arm/boot/dts/orion5x-linkstation-lsgl.dts
+++ b/arch/arm/boot/dts/orion5x-linkstation-lsgl.dts
@@ -82,6 +82,10 @@
gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
};
+&sata {
+ nr-ports = <2>;
+};
+
&ehci1 {
status = "okay";
};
--
2.10.2
^ permalink raw reply related
* [PULL] KVM/ARM updates for 4.9-rc7
From: Radim Krčmář @ 2016-12-01 15:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480584341-32340-1-git-send-email-marc.zyngier@arm.com>
2016-12-01 09:25+0000, Marc Zyngier:
> Paolo, Radim,
>
> Hopefully, this is the last update for 4.9. This time, a single patch
> that prevents bogus acknoledgement of interrupts.
>
> It'd be great if this could make it into v4.9-final
Pulled, thanks.
^ permalink raw reply
* [PATCH/RFC] ARM64: use this_cpu_read in raw_smp_processor_id()
From: Will Deacon @ 2016-12-01 15:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480604407-6022-1-git-send-email-m.szyprowski@samsung.com>
On Thu, Dec 01, 2016 at 04:00:07PM +0100, Marek Szyprowski wrote:
> Direct access to cpu_number entry in per-cpu variables causes boot
> failure on Exynos5433, so replace it with this_cpu_read() macro.
> This approach is also used on x86_64.
Right, but x86 doesn't need to disable preemption in their per-cpu ops
afaik, so they don't take the performance hit.
Is this failure specific to Exynos5433?
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
> This change is needed to get linux-next to boot on Exynos5433, otherwise it
> hangs somewhere in early init. There is even no message on the earlycon.
>
> This issue appeared first on linux-next from 14.11.2016. The tree from
> 11.11.2016 is the last one, which boots on Exynos5433. I've tried to
> debug a bit this issue, but I ran out of ideas.
I suspect the culprit is 57c82954e77f ("arm64: make cpu number a percpu
variable").
>
> Any comments or suggestions are welcome.
>
> Best regards
> Marek Szyprowski
> Samsung R&D Institute Poland
> ---
> arch/arm64/include/asm/smp.h | 7 +------
> 1 file changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
> index a62db952ffcb..d514383d6219 100644
> --- a/arch/arm64/include/asm/smp.h
> +++ b/arch/arm64/include/asm/smp.h
> @@ -37,12 +37,7 @@
>
> DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
>
> -/*
> - * We don't use this_cpu_read(cpu_number) as that has implicit writes to
> - * preempt_count, and associated (compiler) barriers, that we'd like to avoid
> - * the expense of. If we're preemptible, the value can be stale at use anyway.
> - */
> -#define raw_smp_processor_id() (*this_cpu_ptr(&cpu_number))
> +#define raw_smp_processor_id() (this_cpu_read(cpu_number))
I think the issue here is that, in the case of CONFIG_DEBUG_PREEMPT=y,
this_cpu_ptr ends up calling back into raw_smp_processor_id() via
my_cpu_offset, whereas this_cpu_read always uses __my_cpu_offset and avoids
the loop.
The right answer is probably to use raw_cpu_ptr instead, and update the
comment to explain why. Do you have CONFIG_DEBUG_PREEMPT=y?
Will
^ permalink raw reply
* [PATCH v2] USB: OHCI: ohci-s3c2410: remove useless functions
From: Alan Stern @ 2016-12-01 15:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480603590-23924-1-git-send-email-csmanjuvijay@gmail.com>
On Thu, 1 Dec 2016 csmanjuvijay at gmail.com wrote:
> From: Manjunath Goudar <csmanjuvijay@gmail.com>
>
> The ohci_hcd_s3c2410_drv_probe and ohci_hcd_s3c2410_drv_remove
> functions are removed as these are useless functions except calling
> usb_hcd_s3c2410_probe and usb_hcd_s3c2410_remove functions.
>
> The usb_hcd_s3c2410_probe function renamed to ohci_hcd_s3c2410_drv_probe
> and usb_hcd_s3c2410_remove function renamed to ohci_hcd_s3c2410_drv_remove
> for proper naming.
>
> Signed-off-by: Manjunath Goudar <csmanjuvijay@gmail.com>
> Cc: Kukjin Kim <kgene@kernel.org>
> Cc: Krzysztof Kozlowski <krzk@kernel.org>
> Cc: Javier Martinez Canillas <javier@osg.samsung.com>
> Cc: Alan Stern <stern@rowland.harvard.edu>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-samsung-soc at vger.kernel.org
> Cc: linux-usb at vger.kernel.org
> Cc: linux-kernel at vger.kernel.org
>
> ---
> Changelog v1 -> v2:
> Removed checkpatch.pl warnings and errors cleanup code which is not related
> to this patch.
Acked-by: Alan Stern <stern@rowland.harvard.edu>
^ permalink raw reply
* [PATCH v3 0/9] STM32F4 missing clocks
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
From: Gabriel Fernandez <gabriel.fernandez@st.com>
v3:
- restructure the patch series to have only one patch for all bindings changes.
(clk: stm32f4: Update DT bindings documentation)
v2:
- Put post divider in config structure
- Rework patch-set
- add update dt binding documentation
- add clock definition file
- Use composite for pll vco clocks
- For auxiliary clock, allow the possiblity to enable peripheral
clocks at same time (sugested by radek)
- Add vco_in clock (entry frequency for all pll) to simplify the code and clarify clock tree
- Fix missing end of divider tables
This patch-set adds:
- I2S & SAI PLLs
- SDIO & 48 Mhz clocks
- LCD-TFT clock
- I2S & SAI clocks
Gabriel Fernandez (9):
clk: stm32f4: Update DT bindings documentation
clk: stm32f4: Add PLL_I2S & PLL_SAI for STM32F429/469 boards
clk: stm32f4: Add post divisor for I2S & SAI PLLs
clk: stm32f4: Add lcd-tft clock
clk: stm32f4: Add I2S clock
clk: stm32f4: Add SAI clocks
clk: stm32f4: SDIO & 48Mhz clock management for STM32F469 board
ARM: dts: stm32f4: Add external I2S clock
ARM: dts: stm32f4: Include auxiliary stm32f4 clock definition
.../devicetree/bindings/clock/st,stm32-rcc.txt | 15 +
arch/arm/boot/dts/stm32f429.dtsi | 9 +-
drivers/clk/clk-stm32f4.c | 585 ++++++++++++++++++++-
include/dt-bindings/clock/stm32f4-clock.h | 37 ++
4 files changed, 626 insertions(+), 20 deletions(-)
create mode 100644 include/dt-bindings/clock/stm32f4-clock.h
--
1.9.1
^ permalink raw reply
* [PATCH v3 1/9] clk: stm32f4: Update DT bindings documentation
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>
From: Gabriel Fernandez <gabriel.fernandez@st.com>
Creation of dt include file for specific stm32f4 clocks.
These specific clocks are not derived from system clock (SYSCLOCK)
We should use index 1 to use these clocks in DT.
e.g. <&rcc 1 CLK_LSI>
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
Acked-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/clock/st,stm32-rcc.txt | 15 +++++++++
include/dt-bindings/clock/stm32f4-clock.h | 37 ++++++++++++++++++++++
2 files changed, 52 insertions(+)
create mode 100644 include/dt-bindings/clock/stm32f4-clock.h
diff --git a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
index 0532d81..8f93740 100644
--- a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
+++ b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
@@ -17,6 +17,9 @@ Required properties:
property, containing a phandle to the clock device node, an index selecting
between gated clocks and other clocks and an index specifying the clock to
use.
+- clocks: External oscillator clock phandle
+ - high speed external clock signal (HSE)
+ - external I2S clock (I2S_CKIN)
Example:
@@ -25,6 +28,7 @@ Example:
#clock-cells = <2>
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;
+ clocks = <&clk_hse>, <&clk_i2s_ckin>;
};
Specifying gated clocks
@@ -66,6 +70,17 @@ The secondary index is bound with the following magic numbers:
0 SYSTICK
1 FCLK
+ 2 CLK_LSI (low-power clock source)
+ 3 CLK_LSE (generated from a 32.768 kHz low-speed external
+ crystal or ceramic resonator)
+ 4 CLK_HSE_RTC (HSE division factor for RTC clock)
+ 5 CLK_RTC (real-time clock)
+ 6 PLL_VCO_I2S (vco frequency of I2S pll)
+ 7 PLL_VCO_SAI (vco frequency of SAI pll)
+ 8 CLK_LCD (LCD-TFT)
+ 9 CLK_I2S (I2S clocks)
+ 10 CLK_SAI1 (audio clocks)
+ 11 CLK_SAI2
Example:
diff --git a/include/dt-bindings/clock/stm32f4-clock.h b/include/dt-bindings/clock/stm32f4-clock.h
new file mode 100644
index 0000000..5431f00
--- /dev/null
+++ b/include/dt-bindings/clock/stm32f4-clock.h
@@ -0,0 +1,37 @@
+/*
+ * stm32f4-clock.h
+ *
+ * Copyright (C) 2016 STMicroelectronics
+ * Author: Gabriel Fernandez for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+/*
+ * List of clocks wich are not derived from system clock (SYSCLOCK)
+ *
+ * The index of these clocks is the secondary index of DT bindings
+ * (see Documentatoin/devicetree/bindings/clock/st,stm32-rcc.txt)
+ *
+ * e.g:
+ <assigned-clocks = <&rcc 1 CLK_LSE>;
+*/
+
+#ifndef _DT_BINDINGS_CLK_STMF4_H
+#define _DT_BINDINGS_CLK_STMF4_H
+
+#define SYSTICK 0
+#define FCLK 1
+#define CLK_LSI 2
+#define CLK_LSE 3
+#define CLK_HSE_RTC 4
+#define CLK_RTC 5
+#define PLL_VCO_I2S 6
+#define PLL_VCO_SAI 7
+#define CLK_LCD 8
+#define CLK_I2S 9
+#define CLK_SAI1 10
+#define CLK_SAI2 11
+
+#define END_PRIMARY_CLK 12
+
+#endif
--
1.9.1
^ permalink raw reply related
* [PATCH v3 2/9] clk: stm32f4: Add PLL_I2S & PLL_SAI for STM32F429/469 boards
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>
From: Gabriel Fernandez <gabriel.fernandez@st.com>
This patch introduces PLL_I2S and PLL_SAI.
Vco clock of these PLLs can be modify by DT (only n multiplicator,
m divider is still fixed by the boot-loader).
Each PLL has 3 dividers. PLL should be off when we modify the rate.
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
Acked-by: Rob Herring <robh@kernel.org>
---
drivers/clk/clk-stm32f4.c | 351 +++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 334 insertions(+), 17 deletions(-)
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 5eb05db..c2b62cc 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -28,6 +28,14 @@
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
+/*
+ * Include list of clocks wich are not derived from system clock (SYSCLOCK)
+ * The index of these clocks is the secondary index of DT bindings
+ *
+ */
+#include <dt-bindings/clock/stm32f4-clock.h>
+
+#define STM32F4_RCC_CR 0x00
#define STM32F4_RCC_PLLCFGR 0x04
#define STM32F4_RCC_CFGR 0x08
#define STM32F4_RCC_AHB1ENR 0x30
@@ -37,6 +45,8 @@
#define STM32F4_RCC_APB2ENR 0x44
#define STM32F4_RCC_BDCR 0x70
#define STM32F4_RCC_CSR 0x74
+#define STM32F4_RCC_PLLI2SCFGR 0x84
+#define STM32F4_RCC_PLLSAICFGR 0x88
struct stm32f4_gate_data {
u8 offset;
@@ -208,8 +218,6 @@ struct stm32f4_gate_data {
{ STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" },
};
-enum { SYSTICK, FCLK, CLK_LSI, CLK_LSE, CLK_HSE_RTC, CLK_RTC, END_PRIMARY_CLK };
-
/*
* This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx
* have gate bits associated with them. Its combined hweight is 71.
@@ -324,23 +332,312 @@ static struct clk *clk_register_apb_mul(struct device *dev, const char *name,
return clk;
}
-/*
- * Decode current PLL state and (statically) model the state we inherit from
- * the bootloader.
- */
-static void stm32f4_rcc_register_pll(const char *hse_clk, const char *hsi_clk)
+enum {
+ PLL,
+ PLL_I2S,
+ PLL_SAI,
+};
+
+static const struct clk_div_table pll_divp_table[] = {
+ { 0, 2 }, { 1, 4 }, { 2, 6 }, { 3, 8 }, { 0 }
+};
+
+static const struct clk_div_table pll_divr_table[] = {
+ { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 0 }
+};
+
+struct stm32f4_pll {
+ spinlock_t *lock;
+ struct clk_gate gate;
+ u8 offset;
+ u8 bit_rdy_idx;
+ u8 status;
+ u8 n_start;
+};
+
+#define to_stm32f4_pll(_gate) container_of(_gate, struct stm32f4_pll, gate)
+
+struct stm32f4_vco_data {
+ const char *vco_name;
+ u8 offset;
+ u8 bit_idx;
+ u8 bit_rdy_idx;
+};
+
+static const struct stm32f4_vco_data vco_data[] = {
+ { "vco", STM32F4_RCC_PLLCFGR, 24, 25 },
+ { "vco-i2s", STM32F4_RCC_PLLI2SCFGR, 26, 27 },
+ { "vco-sai", STM32F4_RCC_PLLSAICFGR, 28, 29 },
+};
+
+struct stm32f4_div_data {
+ u8 shift;
+ u8 width;
+ u8 flag_div;
+ const struct clk_div_table *div_table;
+};
+
+#define MAX_PLL_DIV 3
+static const struct stm32f4_div_data div_data[MAX_PLL_DIV] = {
+ { 16, 2, 0, pll_divp_table },
+ { 24, 4, CLK_DIVIDER_ONE_BASED, NULL },
+ { 28, 3, 0, pll_divr_table },
+};
+
+struct stm32f4_pll_data {
+ u8 pll_num;
+ u8 n_start;
+ const char *div_name[MAX_PLL_DIV];
+};
+
+static const struct stm32f4_pll_data stm32f429_pll[MAX_PLL_DIV] = {
+ { PLL, 192, { "pll", "pll48", NULL } },
+ { PLL_I2S, 192, { NULL, "plli2s-q", "plli2s-r" } },
+ { PLL_SAI, 49, { NULL, "pllsai-q", "pllsai-r" } },
+};
+
+static const struct stm32f4_pll_data stm32f469_pll[MAX_PLL_DIV] = {
+ { PLL, 50, { "pll", "pll-q", NULL } },
+ { PLL_I2S, 50, { "plli2s-p", "plli2s-q", "plli2s-r" } },
+ { PLL_SAI, 50, { "pllsai-p", "pllsai-q", "pllsai-r" } },
+};
+
+static int stm32f4_pll_is_enabled(struct clk_hw *hw)
+{
+ return clk_gate_ops.is_enabled(hw);
+}
+
+static int stm32f4_pll_enable(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+ int ret = 0;
+ unsigned long reg;
+
+ ret = clk_gate_ops.enable(hw);
+
+ ret = readl_relaxed_poll_timeout_atomic(base + STM32F4_RCC_CR, reg,
+ reg & (1 << pll->bit_rdy_idx), 0, 10000);
+
+ return ret;
+}
+
+static void stm32f4_pll_disable(struct clk_hw *hw)
+{
+ clk_gate_ops.disable(hw);
+}
+
+static unsigned long stm32f4_pll_recalc(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+ unsigned long n;
+
+ n = (readl(base + pll->offset) >> 6) & 0x1ff;
+
+ return parent_rate * n;
+}
+
+static long stm32f4_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+ unsigned long n;
+
+ n = rate / *prate;
+
+ if (n < pll->n_start)
+ n = pll->n_start;
+ else if (n > 432)
+ n = 432;
+
+ return *prate * n;
+}
+
+static int stm32f4_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+
+ unsigned long n;
+ unsigned long val;
+ int pll_state;
+
+ pll_state = stm32f4_pll_is_enabled(hw);
+
+ if (pll_state)
+ stm32f4_pll_disable(hw);
+
+ n = rate / parent_rate;
+
+ val = readl(base + pll->offset) & ~(0x1ff << 6);
+
+ writel(val | ((n & 0x1ff) << 6), base + pll->offset);
+
+ if (pll_state)
+ stm32f4_pll_enable(hw);
+
+ return 0;
+}
+
+static const struct clk_ops stm32f4_pll_gate_ops = {
+ .enable = stm32f4_pll_enable,
+ .disable = stm32f4_pll_disable,
+ .is_enabled = stm32f4_pll_is_enabled,
+ .recalc_rate = stm32f4_pll_recalc,
+ .round_rate = stm32f4_pll_round_rate,
+ .set_rate = stm32f4_pll_set_rate,
+};
+
+struct stm32f4_pll_div {
+ struct clk_divider div;
+ struct clk_hw *hw_pll;
+};
+
+#define to_pll_div_clk(_div) container_of(_div, struct stm32f4_pll_div, div)
+
+static unsigned long stm32f4_pll_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static long stm32f4_pll_div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ return clk_divider_ops.round_rate(hw, rate, prate);
+}
+
+static int stm32f4_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int pll_state, ret;
+
+ struct clk_divider *div = to_clk_divider(hw);
+ struct stm32f4_pll_div *pll_div = to_pll_div_clk(div);
+
+ pll_state = stm32f4_pll_is_enabled(pll_div->hw_pll);
+
+ if (pll_state)
+ stm32f4_pll_disable(pll_div->hw_pll);
+
+ ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
+
+ if (pll_state)
+ stm32f4_pll_enable(pll_div->hw_pll);
+
+ return ret;
+}
+
+const struct clk_ops stm32f4_pll_div_ops = {
+ .recalc_rate = stm32f4_pll_div_recalc_rate,
+ .round_rate = stm32f4_pll_div_round_rate,
+ .set_rate = stm32f4_pll_div_set_rate,
+};
+
+static struct clk_hw *clk_register_pll_div(const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_divider_flags, const struct clk_div_table *table,
+ struct clk_hw *pll_hw, spinlock_t *lock)
{
- unsigned long pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);
+ struct stm32f4_pll_div *pll_div;
+ struct clk_hw *hw;
+ struct clk_init_data init;
+ int ret;
+
+ /* allocate the divider */
+ pll_div = kzalloc(sizeof(*pll_div), GFP_KERNEL);
+ if (!pll_div)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &stm32f4_pll_div_ops;
+ init.flags = flags;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ /* struct clk_divider assignments */
+ pll_div->div.reg = reg;
+ pll_div->div.shift = shift;
+ pll_div->div.width = width;
+ pll_div->div.flags = clk_divider_flags;
+ pll_div->div.lock = lock;
+ pll_div->div.table = table;
+ pll_div->div.hw.init = &init;
+
+ pll_div->hw_pll = pll_hw;
+
+ /* register the clock */
+ hw = &pll_div->div.hw;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ kfree(pll_div);
+ hw = ERR_PTR(ret);
+ }
+
+ return hw;
+}
+
+static struct clk_hw *stm32f4_rcc_register_pll(const char *pllsrc,
+ const struct stm32f4_pll_data *data, spinlock_t *lock)
+{
+ struct stm32f4_pll *pll;
+ struct clk_init_data init = { NULL };
+ void __iomem *reg;
+ struct clk_hw *pll_hw;
+ int ret;
+ int i;
+ const struct stm32f4_vco_data *vco;
+
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ vco = &vco_data[data->pll_num];
+
+ init.name = vco->vco_name;
+ init.ops = &stm32f4_pll_gate_ops;
+ init.flags = CLK_SET_RATE_GATE;
+ init.parent_names = &pllsrc;
+ init.num_parents = 1;
+
+ pll->gate.lock = lock;
+ pll->gate.reg = base + STM32F4_RCC_CR;
+ pll->gate.bit_idx = vco->bit_idx;
+ pll->gate.hw.init = &init;
+
+ pll->offset = vco->offset;
+ pll->n_start = data->n_start;
+ pll->bit_rdy_idx = vco->bit_rdy_idx;
+ pll->status = (readl(base + STM32F4_RCC_CR) >> vco->bit_idx) & 0x1;
- unsigned long pllm = pllcfgr & 0x3f;
- unsigned long plln = (pllcfgr >> 6) & 0x1ff;
- unsigned long pllp = BIT(((pllcfgr >> 16) & 3) + 1);
- const char *pllsrc = pllcfgr & BIT(22) ? hse_clk : hsi_clk;
- unsigned long pllq = (pllcfgr >> 24) & 0xf;
+ reg = base + pll->offset;
- clk_register_fixed_factor(NULL, "vco", pllsrc, 0, plln, pllm);
- clk_register_fixed_factor(NULL, "pll", "vco", 0, 1, pllp);
- clk_register_fixed_factor(NULL, "pll48", "vco", 0, 1, pllq);
+ pll_hw = &pll->gate.hw;
+ ret = clk_hw_register(NULL, pll_hw);
+ if (ret) {
+ kfree(pll);
+ return ERR_PTR(ret);
+ }
+
+ for (i = 0; i < MAX_PLL_DIV; i++)
+ if (data->div_name[i])
+ clk_register_pll_div(data->div_name[i],
+ vco->vco_name,
+ 0,
+ reg,
+ div_data[i].shift,
+ div_data[i].width,
+ div_data[i].flag_div,
+ div_data[i].div_table,
+ pll_hw,
+ lock);
+ return pll_hw;
}
/*
@@ -615,18 +912,21 @@ struct stm32f4_clk_data {
const struct stm32f4_gate_data *gates_data;
const u64 *gates_map;
int gates_num;
+ const struct stm32f4_pll_data *pll_data;
};
static const struct stm32f4_clk_data stm32f429_clk_data = {
.gates_data = stm32f429_gates,
.gates_map = stm32f42xx_gate_map,
.gates_num = ARRAY_SIZE(stm32f429_gates),
+ .pll_data = stm32f429_pll,
};
static const struct stm32f4_clk_data stm32f469_clk_data = {
.gates_data = stm32f469_gates,
.gates_map = stm32f46xx_gate_map,
.gates_num = ARRAY_SIZE(stm32f469_gates),
+ .pll_data = stm32f469_pll,
};
static const struct of_device_id stm32f4_of_match[] = {
@@ -647,6 +947,9 @@ static void __init stm32f4_rcc_init(struct device_node *np)
int n;
const struct of_device_id *match;
const struct stm32f4_clk_data *data;
+ unsigned long pllcfgr;
+ const char *pllsrc;
+ unsigned long pllm;
base = of_iomap(np, 0);
if (!base) {
@@ -677,7 +980,21 @@ static void __init stm32f4_rcc_init(struct device_node *np)
clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0,
16000000, 160000);
- stm32f4_rcc_register_pll(hse_clk, "hsi");
+ pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);
+ pllsrc = pllcfgr & BIT(22) ? hse_clk : "hsi";
+ pllm = pllcfgr & 0x3f;
+
+ clk_hw_register_fixed_factor(NULL, "vco_in", pllsrc,
+ 0, 1, pllm);
+
+ stm32f4_rcc_register_pll("vco_in", &data->pll_data[0],
+ &stm32f4_clk_lock);
+
+ clks[PLL_VCO_I2S] = stm32f4_rcc_register_pll("vco_in",
+ &data->pll_data[1], &stm32f4_clk_lock);
+
+ clks[PLL_VCO_SAI] = stm32f4_rcc_register_pll("vco_in",
+ &data->pll_data[2], &stm32f4_clk_lock);
sys_parents[1] = hse_clk;
clk_register_mux_table(
--
1.9.1
^ permalink raw reply related
* [PATCH v3 3/9] clk: stm32f4: Add post divisor for I2S & SAI PLLs
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>
From: Gabriel Fernandez <gabriel.fernandez@st.com>
This patch adds post dividers of I2S & SAI PLLs.
These dividers are managed by a dedicated register (RCC_DCKCFGR).
The PLL should be off before a set rate.
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
drivers/clk/clk-stm32f4.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index c2b62cc..98856ac 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -47,6 +47,7 @@
#define STM32F4_RCC_CSR 0x74
#define STM32F4_RCC_PLLI2SCFGR 0x84
#define STM32F4_RCC_PLLSAICFGR 0x88
+#define STM32F4_RCC_DCKCFGR 0x8c
struct stm32f4_gate_data {
u8 offset;
@@ -357,6 +358,18 @@ struct stm32f4_pll {
#define to_stm32f4_pll(_gate) container_of(_gate, struct stm32f4_pll, gate)
+struct stm32f4_pll_post_div_data {
+ u8 pll_num;
+ const char *name;
+ const char *parent;
+ u8 flag;
+ u8 offset;
+ u8 shift;
+ u8 width;
+ u8 flag_div;
+ const struct clk_div_table *div_table;
+};
+
struct stm32f4_vco_data {
const char *vco_name;
u8 offset;
@@ -370,6 +383,18 @@ struct stm32f4_vco_data {
{ "vco-sai", STM32F4_RCC_PLLSAICFGR, 28, 29 },
};
+#define MAX_POST_DIV 3
+static const struct stm32f4_pll_post_div_data post_div_data[MAX_POST_DIV] = {
+ { PLL_I2S, "plli2s-q-div", "plli2s-q", CLK_SET_RATE_PARENT,
+ STM32F4_RCC_DCKCFGR, 0, 5, 0, NULL},
+
+ { PLL_SAI, "pllsai-q-div", "pllsai-q", CLK_SET_RATE_PARENT,
+ STM32F4_RCC_DCKCFGR, 8, 5, 0, NULL },
+
+ { PLL_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT,
+ STM32F4_RCC_DCKCFGR, 16, 2, CLK_DIVIDER_POWER_OF_TWO},
+};
+
struct stm32f4_div_data {
u8 shift;
u8 width;
@@ -996,6 +1021,23 @@ static void __init stm32f4_rcc_init(struct device_node *np)
clks[PLL_VCO_SAI] = stm32f4_rcc_register_pll("vco_in",
&data->pll_data[2], &stm32f4_clk_lock);
+ for (n = 0; n < MAX_POST_DIV; n++) {
+ const struct stm32f4_pll_post_div_data *post_div;
+
+ post_div = &post_div_data[n];
+
+ clk_register_pll_div(post_div->name,
+ post_div->parent,
+ post_div->flag,
+ base + post_div->offset,
+ post_div->shift,
+ post_div->width,
+ post_div->flag_div,
+ post_div->div_table,
+ clks[post_div->pll_num],
+ &stm32f4_clk_lock);
+ }
+
sys_parents[1] = hse_clk;
clk_register_mux_table(
NULL, "sys", sys_parents, ARRAY_SIZE(sys_parents), 0,
--
1.9.1
^ permalink raw reply related
* [PATCH v3 4/9] clk: stm32f4: Add lcd-tft clock
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>
From: Gabriel Fernandez <gabriel.fernandez@st.com>
This patch introduces lcd-tft clock for stm32f4 soc.
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
drivers/clk/clk-stm32f4.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 117 insertions(+)
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 98856ac..86244fc 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -933,11 +933,42 @@ static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name,
"no-clock", "lse", "lsi", "hse-rtc"
};
+static const char *lcd_parent[1] = { "pllsai-r-div" };
+
+struct stm32_aux_clk {
+ int idx;
+ const char *name;
+ const char * const *parent_names;
+ int num_parents;
+ int offset_mux;
+ u8 shift;
+ u8 mask;
+ int offset_gate;
+ u8 bit_idx;
+ unsigned long flags;
+};
+
struct stm32f4_clk_data {
const struct stm32f4_gate_data *gates_data;
const u64 *gates_map;
int gates_num;
const struct stm32f4_pll_data *pll_data;
+ const struct stm32_aux_clk *aux_clk;
+ int aux_clk_num;
+};
+
+#define NONE -1
+#define NO_IDX NONE
+#define NO_MUX NONE
+#define NO_GATE NONE
+
+static const struct stm32_aux_clk stm32f429_aux_clk[] = {
+ {
+ CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
+ NO_MUX, 0, 0,
+ STM32F4_RCC_APB2ENR, 26,
+ CLK_SET_RATE_PARENT
+ },
};
static const struct stm32f4_clk_data stm32f429_clk_data = {
@@ -945,6 +976,8 @@ struct stm32f4_clk_data {
.gates_map = stm32f42xx_gate_map,
.gates_num = ARRAY_SIZE(stm32f429_gates),
.pll_data = stm32f429_pll,
+ .aux_clk = stm32f429_aux_clk,
+ .aux_clk_num = ARRAY_SIZE(stm32f429_aux_clk),
};
static const struct stm32f4_clk_data stm32f469_clk_data = {
@@ -952,6 +985,8 @@ struct stm32f4_clk_data {
.gates_map = stm32f46xx_gate_map,
.gates_num = ARRAY_SIZE(stm32f469_gates),
.pll_data = stm32f469_pll,
+ .aux_clk = stm32f429_aux_clk,
+ .aux_clk_num = ARRAY_SIZE(stm32f429_aux_clk),
};
static const struct of_device_id stm32f4_of_match[] = {
@@ -966,6 +1001,66 @@ struct stm32f4_clk_data {
{}
};
+static struct clk_hw *stm32_register_aux_clk(const char *name,
+ const char * const *parent_names, int num_parents,
+ int offset_mux, u8 shift, u8 mask,
+ int offset_gate, u8 bit_idx,
+ unsigned long flags, spinlock_t *lock)
+{
+ struct clk_hw *hw;
+ struct clk_gate *gate;
+ struct clk_mux *mux = NULL;
+ struct clk_hw *mux_hw = NULL, *gate_hw = NULL;
+ const struct clk_ops *mux_ops = NULL, *gate_ops = NULL;
+
+ if (offset_gate != NO_GATE) {
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ hw = ERR_PTR(-EINVAL);
+ goto fail;
+ }
+
+ gate->reg = base + offset_gate;
+ gate->bit_idx = bit_idx;
+ gate->flags = 0;
+ gate->lock = lock;
+ gate_hw = &gate->hw;
+ gate_ops = &clk_gate_ops;
+ }
+
+ if (offset_mux != NO_MUX) {
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux) {
+ kfree(gate);
+ hw = ERR_PTR(-EINVAL);
+ goto fail;
+ }
+
+ mux->reg = base + offset_mux;
+ mux->shift = shift;
+ mux->mask = mask;
+ mux->flags = 0;
+ mux_hw = &mux->hw;
+ mux_ops = &clk_mux_ops;
+ }
+
+ if (mux_hw == NULL && gate_hw == NULL)
+ return ERR_PTR(-EINVAL);
+
+ hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
+ mux_hw, mux_ops,
+ NULL, NULL,
+ gate_hw, gate_ops,
+ flags);
+
+ if (IS_ERR(hw)) {
+ kfree(gate);
+ kfree(mux);
+ }
+fail:
+ return hw;
+}
+
static void __init stm32f4_rcc_init(struct device_node *np)
{
const char *hse_clk;
@@ -1121,6 +1216,28 @@ static void __init stm32f4_rcc_init(struct device_node *np)
goto fail;
}
+ for (n = 0; n < data->aux_clk_num; n++) {
+ const struct stm32_aux_clk *aux_clk;
+ struct clk_hw *hw;
+
+ aux_clk = &data->aux_clk[n];
+
+ hw = stm32_register_aux_clk(aux_clk->name,
+ aux_clk->parent_names, aux_clk->num_parents,
+ aux_clk->offset_mux, aux_clk->shift,
+ aux_clk->mask, aux_clk->offset_gate,
+ aux_clk->bit_idx, aux_clk->flags,
+ &stm32f4_clk_lock);
+
+ if (IS_ERR(hw)) {
+ pr_warn("Unable to register %s clk\n", aux_clk->name);
+ continue;
+ }
+
+ if (aux_clk->idx != NO_IDX)
+ clks[aux_clk->idx] = hw;
+ }
+
of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL);
return;
fail:
--
1.9.1
^ permalink raw reply related
* [PATCH v3 5/9] clk: stm32f4: Add I2S clock
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>
From: Gabriel Fernandez <gabriel.fernandez@st.com>
This patch introduces I2S clock for stm32f4 soc.
The I2S clock could be derived from an external clock or from pll-i2s
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
drivers/clk/clk-stm32f4.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 86244fc..3063b30 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -935,6 +935,8 @@ static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name,
static const char *lcd_parent[1] = { "pllsai-r-div" };
+static const char *i2s_parents[2] = { "plli2s-r", NULL };
+
struct stm32_aux_clk {
int idx;
const char *name;
@@ -969,6 +971,12 @@ struct stm32f4_clk_data {
STM32F4_RCC_APB2ENR, 26,
CLK_SET_RATE_PARENT
},
+ {
+ CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
+ STM32F4_RCC_CFGR, 23, 1,
+ NO_GATE, 0,
+ CLK_SET_RATE_PARENT
+ },
};
static const struct stm32f4_clk_data stm32f429_clk_data = {
@@ -1063,7 +1071,7 @@ static struct clk_hw *stm32_register_aux_clk(const char *name,
static void __init stm32f4_rcc_init(struct device_node *np)
{
- const char *hse_clk;
+ const char *hse_clk, *i2s_in_clk;
int n;
const struct of_device_id *match;
const struct stm32f4_clk_data *data;
@@ -1098,6 +1106,10 @@ static void __init stm32f4_rcc_init(struct device_node *np)
hse_clk = of_clk_get_parent_name(np, 0);
+ i2s_in_clk = of_clk_get_parent_name(np, 1);
+
+ i2s_parents[1] = i2s_in_clk;
+
clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0,
16000000, 160000);
pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);
--
1.9.1
^ permalink raw reply related
* [PATCH v3 6/9] clk: stm32f4: Add SAI clocks
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>
From: Gabriel Fernandez <gabriel.fernandez@st.com>
This patch introduces SAI clocks for stm32f4 socs.
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
drivers/clk/clk-stm32f4.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 3063b30..02339d1 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -937,6 +937,9 @@ static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name,
static const char *i2s_parents[2] = { "plli2s-r", NULL };
+static const char *sai_parents[4] = { "pllsai-q-div", "plli2s-q-div", NULL,
+ "no-clock" };
+
struct stm32_aux_clk {
int idx;
const char *name;
@@ -977,6 +980,18 @@ struct stm32f4_clk_data {
NO_GATE, 0,
CLK_SET_RATE_PARENT
},
+ {
+ CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
+ STM32F4_RCC_DCKCFGR, 20, 3,
+ STM32F4_RCC_APB2ENR, 22,
+ CLK_SET_RATE_PARENT
+ },
+ {
+ CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
+ STM32F4_RCC_DCKCFGR, 22, 3,
+ STM32F4_RCC_APB2ENR, 22,
+ CLK_SET_RATE_PARENT
+ },
};
static const struct stm32f4_clk_data stm32f429_clk_data = {
@@ -1109,6 +1124,7 @@ static void __init stm32f4_rcc_init(struct device_node *np)
i2s_in_clk = of_clk_get_parent_name(np, 1);
i2s_parents[1] = i2s_in_clk;
+ sai_parents[2] = i2s_in_clk;
clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0,
16000000, 160000);
--
1.9.1
^ permalink raw reply related
* [PATCH v3 7/9] clk: stm32f4: SDIO & 48Mhz clock management for STM32F469 board
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>
From: Gabriel Fernandez <gabriel.fernandez@st.com>
In the stm32f469 soc, the 48Mhz clock could be derived from pll-q or
from pll-sai-p.
The SDIO clock could be also derived from 48Mhz or from sys clock.
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
drivers/clk/clk-stm32f4.c | 49 ++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 46 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 02339d1..161449d 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -206,7 +206,7 @@ struct stm32f4_gate_data {
{ STM32F4_RCC_APB2ENR, 8, "adc1", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" },
- { STM32F4_RCC_APB2ENR, 11, "sdio", "pll48" },
+ { STM32F4_RCC_APB2ENR, 11, "sdio", "sdmux" },
{ STM32F4_RCC_APB2ENR, 12, "spi1", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 13, "spi4", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 14, "syscfg", "apb2_div" },
@@ -940,6 +940,10 @@ static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name,
static const char *sai_parents[4] = { "pllsai-q-div", "plli2s-q-div", NULL,
"no-clock" };
+static const char *pll48_parents[2] = { "pll-q", "pllsai-p" };
+
+static const char *sdmux_parents[2] = { "pll48", "sys" };
+
struct stm32_aux_clk {
int idx;
const char *name;
@@ -994,6 +998,45 @@ struct stm32f4_clk_data {
},
};
+static const struct stm32_aux_clk stm32f469_aux_clk[] = {
+ {
+ CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
+ NO_MUX, 0, 0,
+ STM32F4_RCC_APB2ENR, 26,
+ CLK_SET_RATE_PARENT
+ },
+ {
+ CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
+ STM32F4_RCC_CFGR, 23, 1,
+ NO_GATE, 0,
+ CLK_SET_RATE_PARENT
+ },
+ {
+ CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
+ STM32F4_RCC_DCKCFGR, 20, 3,
+ STM32F4_RCC_APB2ENR, 22,
+ CLK_SET_RATE_PARENT
+ },
+ {
+ CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
+ STM32F4_RCC_DCKCFGR, 22, 3,
+ STM32F4_RCC_APB2ENR, 22,
+ CLK_SET_RATE_PARENT
+ },
+ {
+ NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
+ STM32F4_RCC_DCKCFGR, 27, 1,
+ NO_GATE, 0,
+ 0
+ },
+ {
+ NO_IDX, "sdmux", sdmux_parents, ARRAY_SIZE(sdmux_parents),
+ STM32F4_RCC_DCKCFGR, 28, 1,
+ NO_GATE, 0,
+ 0
+ },
+};
+
static const struct stm32f4_clk_data stm32f429_clk_data = {
.gates_data = stm32f429_gates,
.gates_map = stm32f42xx_gate_map,
@@ -1008,8 +1051,8 @@ struct stm32f4_clk_data {
.gates_map = stm32f46xx_gate_map,
.gates_num = ARRAY_SIZE(stm32f469_gates),
.pll_data = stm32f469_pll,
- .aux_clk = stm32f429_aux_clk,
- .aux_clk_num = ARRAY_SIZE(stm32f429_aux_clk),
+ .aux_clk = stm32f469_aux_clk,
+ .aux_clk_num = ARRAY_SIZE(stm32f469_aux_clk),
};
static const struct of_device_id stm32f4_of_match[] = {
--
1.9.1
^ permalink raw reply related
* [PATCH v3 8/9] ARM: dts: stm32f4: Add external I2S clock
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>
From: Gabriel Fernandez <gabriel.fernandez@st.com>
This patch adds an external I2S clock in the DT.
The I2S clock could be derived from an external I2S clock or by I2S pll.
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
arch/arm/boot/dts/stm32f429.dtsi | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index e4dae0e..7c7dfbd 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -68,6 +68,12 @@
compatible = "fixed-clock";
clock-frequency = <32000>;
};
+
+ clk_i2s_ckin: i2s-ckin {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
};
soc {
@@ -362,7 +368,7 @@
#clock-cells = <2>;
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;
- clocks = <&clk_hse>;
+ clocks = <&clk_hse>, <&clk_i2s_ckin>;
st,syscfg = <&pwrcfg>;
};
--
1.9.1
^ permalink raw reply related
* [PATCH v3 9/9] ARM: dts: stm32f4: Include auxiliary stm32f4 clock definition
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>
From: Gabriel Fernandez <gabriel.fernandez@st.com>
This patch include auxiliary clock definition (clocks which are not derived
from system clock.
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
arch/arm/boot/dts/stm32f429.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index 7c7dfbd..223dc12 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -48,6 +48,7 @@
#include "skeleton.dtsi"
#include "armv7-m.dtsi"
#include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
+#include <dt-bindings/clock/stm32f4-clock.h>
/ {
clocks {
--
1.9.1
^ permalink raw reply related
* [PATCH 0/5] Meson GXL and GXM USB support
From: Rob Herring @ 2016-12-01 15:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAFBinCC8c2sXgo80LMMg=jqZ2hr8eLM_2g03H1J99m4xxFGYFA@mail.gmail.com>
On Wed, Nov 30, 2016 at 11:49:03PM +0100, Martin Blumenstingl wrote:
> On Wed, Nov 30, 2016 at 11:22 PM, Rob Herring <robh@kernel.org> wrote:
> > On Sun, Nov 27, 2016 at 11:42:02PM +0100, Martin Blumenstingl wrote:
> >> Hello Kishon,
> >>
> >> On Sat, Nov 26, 2016 at 3:56 PM, Martin Blumenstingl
> >> <martin.blumenstingl@googlemail.com> wrote:
> >> > USB support on GXL and GXM differs a lot from Meson8b and GXBB:
> >> > The most obvious change is that GXL and GXM now have one dwc3
> >> > controller and one dwc2 controller (instead of two dwc2 controllers).
> >> > With that there are also new USB PHYs.
> >> >
> >> > Due to lack of hardware I was only able to test this on a board with
> >> > GXM, but as far as I understand the hardware my preparations should be
> >> > correct (so it should also work on GXL).
> >> >
> >> > dwc2 will probably stay unused on most GXM devices since it's limited
> >> > to device mode via some dwc2 hardware configuration register.
> >> >
> >> > dwc3 is probably used on all devices, even if there is more than just
> >> > one USB port. dwc3 has a built-in USB2 hub - on GXL this hub has two
> >> > ports enabled, while on GXM there are three ports enabled (see below
> >
> > This hub is an actual USB hub? If so, then you should probably model the
> > USB bus topology (which we have a binding definition for).
> (the following explanation is based on a) what I found is going on in
> the hardware registers b) reading the vendor drivers - unfortunately
> there are no datasheets available which could give more details).
> lsusb on my GXM gives:
> ...
> Hub Port Status:
> Port 1: 0000.0100 power
> Port 2: 0000.0100 power
> Port 3: 0000.0100 power
>
> The layout looks like this:
> dwc3 provides a USB hub with 2 (on GXL) or 3 (on GXM) USB ports.
> Each of the port is driven by a PHY (port 1 = abp at 0x78000, port2 =
> abp at 0x78020, etc...).
>
> On GXM USB2 PHY port 3 = abp at 0x78040 is connected to the third dwc3 hub port.
> On GXL PHY port 3 = abp at 0x78040 is connected to the dwc2 (I could not
> prove this yet as I don't have access to any GXL hardware).
>
> So the answer is: we don't have an actual USB hub here (as this hub is
> provided by dwc3), but rather a set of PHYs which is assigned to
> dwc3's hub (if we don't configure *all* PHYs then none of the USB
> ports provided by the dwc3 hub works).
>
> Could you please point me to the USB bus topology binding (is it the
> one described in usb-device.txt)?
Yes.
>
> >> > for lsusb output). There are no USB3 ports enabled in the dwc3 hardware
> >> > configuration, meaning that the SoC is limited to high-speed mode.
> >> > On my GXM device the dwc3 hardware configuration forces it into "host
> >> > only" mode.
> >> >
> >> > The SoCs contain two PHY blocks: one USB3 PHY and up to four USB2 PHYs
> >> > (on GXM there are only three enabled, but the registers should support
> >> > up to four).
> >> > The USB3 PHY also handles the OTG interrupts, but since dwc3's hardware
> >> > configuration enforces "host only" mode I was not able to test this. It
> >> > simply takes care of an interrupt and then notifies all related PHYs
> >> > about the new mode.
> >> > The USB2 PHY block is a bit different: I created one PHY driver which
> >> > spans all "PHY ports" because the handling is a bit tricky. It turns
> >> > out that for each available USB port in dwc3's hub the corresponding
> >> > PHY must be enabled (even if there is no physical port - in my case
> >> > port 3 is not connected to anything, but disabling the PHY breaks
> >> > ports 1 and 2 as well).
> >> > I decided not not pass the USB2 PHYs directly to dwc3 due to three
> >> > reasons: 1. the USB3 PHY (which holds a reference to all relevant
> >> > USB2 PHY ports) controls the mode of the USB2 PHY ports (since both
> >> > are used with the same controller and thus it makes sense to keep the
> >> > mode consistent across all ports) 2. the dwc3 driver does not support
> >> > passing multiple USB2 PHYs (only one USB2 and one USB3 PHY can be
> >> > passed to it) 3. it is similar to how the vendor reference driver
> >> > manages the PHYs. Please note that this coupling is not a fixed, this
> >> > is all configurable via devicetree (so if the third USB2 PHY has to
> >> > be passed two the dwc2 controller then this is still possible by
> >> > just moving on PHY reference in the .dts).
> >> after not staring at my own code for 24 hours I realized this:
> >> (I went through quite a few iterations before getting these drivers to work)
> >> I'm basically re-modelling an "USB PHY hub" with my USB3 PHY driver
> >> (there's one "upstream" PHY interface which is passed to dwc3 and
> >> multiple downstream PHYs, each for one port on dwc3's internal hub).
> >> With this approach I could split each of the the USB2s into separate
> >> nodes again (instead of one devicetree node with #phy-cells = <1>) as
> >> the USB3 PHY is taking care of that special "we have to enable all
> >> ports or no port will be usable".
> >>
> >> We could go even one step further: why implement this in the Meson GXL
> >> specific PHY driver - why not implement a generic "phy-hub" driver
> >> (which would be valid whenever the PHY controller has to manage
> >> multiple PHYs at once, but wants to keep them all in a consistent
> >> state).
> >> The devicetree could look like this:
> >> usb2_phy_hub: phy at 0 {
> >> compatible = "phy-hub";
> >> phys = <&other_phy1>, <&other_phy 2>;
> >> };
> >>
> >> &dwc3 {
> >> phys = <&usb2_phy_hub>, <&usb3_phy0>;
> >> phy-names = "usb2-phy", "usb3-phy";
> >> };
> >
> > I'm okay with a hub if it is modeled as a USB hub. Here though, it
> > looks like you are just trying to group things which doesn't need to be
> > in DT.
> I hope my answer above makes things more clear
Yes, I thought there was some heirarchy here, but it seems not.
So you should just list the 3 phys at the controller. The controller
has 3 ports and you have a phy for each port. The fact that they all
need to be on/initialized is a quirk and shouldn't mean that you create
some heirarchy in DT.
> >> The generic phy-hub driver would then implement all phy_ops callbacks
> >> and pass then to each of it's downstream PHYs.
> >
> > You can have generic drivers without a generic binding.
> So you'd rather implement a generic driver which would provide
> functions like of_create_grouped_phy(struct device_node *np) which
> would implement the grouping logic as described (but has no binding
> itself, but rather relies on the actual platform driver taking care of
> creating that binding and re-using generic code)?
Right.
Rob
^ permalink raw reply
* [PATCH] arm64: smp: Prevent raw_smp_processor_id() recursion
From: Robin Murphy @ 2016-12-01 15:55 UTC (permalink / raw)
To: linux-arm-kernel
Under CONFIG_DEBUG_PREEMPT=y, this_cpu_ptr() ends up calling back into
raw_smp_processor_id(), resulting in some hilariously catastrophic
infinite recursion. In the normal case, we have:
#define this_cpu_ptr(ptr) raw_cpu_ptr(ptr)
and everything is dandy. However for CONFIG_DEBUG_PREEMPT, this_cpu_ptr()
is defined in terms of my_cpu_offset, wherein the fun begins:
#define my_cpu_offset per_cpu_offset(smp_processor_id())
...
#define smp_processor_id() debug_smp_processor_id()
...
notrace unsigned int debug_smp_processor_id(void)
{
return check_preemption_disabled("smp_processor_id", "");
...
notrace static unsigned int check_preemption_disabled(const char *what1,
const char *what2)
{
int this_cpu = raw_smp_processor_id();
and bang. Use raw_cpu_ptr() directly to avoid that.
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
Since I just reproduced this locally to verify Will's suggestion, it
seemed I might as well just write it up as a patch :)
arch/arm64/include/asm/smp.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index a62db952ffcb..d050d720a1b4 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -41,8 +41,10 @@ DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
* We don't use this_cpu_read(cpu_number) as that has implicit writes to
* preempt_count, and associated (compiler) barriers, that we'd like to avoid
* the expense of. If we're preemptible, the value can be stale at use anyway.
+ * And we can't use this_cpu_ptr() either, as that winds up recursing back
+ * here under CONFIG_DEBUG_PREEMPT=y.
*/
-#define raw_smp_processor_id() (*this_cpu_ptr(&cpu_number))
+#define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number))
struct seq_file;
--
2.10.2.dirty
^ permalink raw reply related
* [PATCH v5 net-next 7/7] ARM64: dts: marvell: Add network support for Armada 3700
From: Marcin Wojtas @ 2016-12-01 16:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <f205231e640a2324b8f007073cf54b166a263ed4.1480542157.git-series.gregory.clement@free-electrons.com>
Hi Gregory,
2016-11-30 22:42 GMT+01:00 Gregory CLEMENT <gregory.clement@free-electrons.com>:
> Add neta nodes for network support both in device tree for the SoC and
> the board.
>
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
> arch/arm64/boot/dts/marvell/armada-3720-db.dts | 23 +++++++++++++++++++-
> arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 23 +++++++++++++++++++-
> 2 files changed, 46 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
> index 1372e9a6aaa4..c8b82e4145de 100644
> --- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
> +++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
> @@ -81,3 +81,26 @@
> &pcie0 {
> status = "okay";
> };
> +
> +&mdio {
> + status = "okay";
> + phy0: ethernet-phy at 0 {
> + reg = <0>;
> + };
> +
> + phy1: ethernet-phy at 1 {
> + reg = <1>;
> + };
> +};
> +
> +ð0 {
> + phy-mode = "rgmii-id";
> + phy = <&phy0>;
> + status = "okay";
> +};
> +
> +ð1 {
> + phy-mode = "rgmii-id";
Should be "sgmii".
Best regards,
Marcin
^ permalink raw reply
* [PATCH v5 net-next 0/7] Support Armada 37xx SoC (ARMv8 64-bits) in mvneta driver
From: Marcin Wojtas @ 2016-12-01 16:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.0270f6d2413a709521fe2c8c17fbebea6f2e78d1.1480542157.git-series.gregory.clement@free-electrons.com>
Hi Gregory,
Checked on a388-gp with and without HWBM, also both ports work on
a3700 (second one after changing to sgmii).
Tested-by: Marcin Wojtas <mw@semihalf.com>
Best regards,
Marcin
2016-11-30 22:42 GMT+01:00 Gregory CLEMENT <gregory.clement@free-electrons.com>:
> Hi,
>
> The Armada 37xx is a new ARMv8 SoC from Marvell using same network
> controller as the older Armada 370/38x/XP SoCs. This series adapts the
> driver in order to be able to use it on this new SoC. The main changes
> are:
>
> - 64-bits support: the first patches allow using the driver on a 64-bit
> architecture.
>
> - MBUS support: the mbus configuration is different on Armada 37xx
> from the older SoCs.
>
> - per cpu interrupt: Armada 37xx do not support per cpu interrupt for
> the NETA IP, the non-per-CPU behavior was added back.
>
> The first patch is an optimization in the rx path in swbm mode.
> The second patch remove unnecessary allocation for HWBM.
> The first item is solved by patches 4 and 5.
> The 2 last items are solved by patch 6.
> In patch 7 the dt support is added.
>
> Beside Armada 37xx, this series have been again tested on Armada XP
> and Armada 38x (with Hardware Buffer Management and with Software
> Buffer Management).
>
> This is the 5th version of the series:
> - 1st version:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/469588.html
>
> - 2nd version:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470476.html
>
> - 3rd version:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470901.html
>
> - 4th version:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/471039.html
>
> Changelog:
> v4 -> v5:
> - remove unnecessary cast in patch 3
>
> v3 -> v4:
> - Adding new patch: "net: mvneta: do not allocate buffer in rxq init
> with HWBM"
>
> - Simplify the HWBM case in patch 3 as suggested by Marcin
>
> v2 -> v3:
> - Adding patch 1 "Optimize rx path for small frame"
>
> - Fix the kbuild error by moving the "phys_addr += pp->rx_offset_correction;"
> line from patch 2 to patch 3 where rx_offset_correction is introduced.
>
> - Move the memory allocation of the buf_virt_addr of the rxq to be
> called by the probe function in order to avoid a memory leak.
>
> Thanks,
>
> Gregory
>
> Gregory CLEMENT (5):
> net: mvneta: Optimize rx path for small frame
> net: mvneta: Do not allocate buffer in rxq init with HWBM
> net: mvneta: Use cacheable memory to store the rx buffer virtual address
> net: mvneta: Only disable mvneta_bm for 64-bits
> ARM64: dts: marvell: Add network support for Armada 3700
>
> Marcin Wojtas (2):
> net: mvneta: Convert to be 64 bits compatible
> net: mvneta: Add network support for Armada 3700 SoC
>
> Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt | 7 +-
> arch/arm64/boot/dts/marvell/armada-3720-db.dts | 23 +++++-
> arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 23 +++++-
> drivers/net/ethernet/marvell/Kconfig | 10 +-
> drivers/net/ethernet/marvell/mvneta.c | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
> 5 files changed, 305 insertions(+), 102 deletions(-)
>
> base-commit: 436accebb53021ef7c63535f60bda410aa87c136
> --
> git-series 0.8.10
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox