* [PATCH] ARM: OMAP2+: add missing ARCH_HAS_OPP
From: Nishanth Menon @ 2014-01-29 13:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389816038-17363-1-git-send-email-nm@ti.com>
Hi Tony,
On 01/15/2014 02:00 PM, Nishanth Menon wrote:
> OMAP5, DRA7, AM43xx all have OPPs. So select the same to allow SoC
> only configuration boot to work with OPP.
>
> Reported-by: Nikhil Devshatwar <nikhil.nd@ti.com>
> Signed-off-by: Nishanth Menon <nm@ti.com>
> ---
>
> For DRA7, depends on: https://patchwork.kernel.org/patch/3465411/
Considering that dependent patch is now on linus master,
a gentle ping -> The patch does apply on latest linus master commit
0e47c969c65e213421450c31043353ebe3c67e0c
patchworks reference: https://patchwork.kernel.org/patch/3493581/
>
> arch/arm/mach-omap2/Kconfig | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
> index 35c23e5..66a9c4a 100644
> --- a/arch/arm/mach-omap2/Kconfig
> +++ b/arch/arm/mach-omap2/Kconfig
> @@ -50,6 +50,7 @@ config SOC_OMAP5
> bool "TI OMAP5"
> depends on ARCH_MULTI_V7
> select ARCH_OMAP2PLUS
> + select ARCH_HAS_OPP
> select ARM_CPU_SUSPEND if PM
> select ARM_GIC
> select CPU_V7
> @@ -63,6 +64,7 @@ config SOC_AM33XX
> bool "TI AM33XX"
> depends on ARCH_MULTI_V7
> select ARCH_OMAP2PLUS
> + select ARCH_HAS_OPP
> select ARM_CPU_SUSPEND if PM
> select CPU_V7
> select MULTI_IRQ_HANDLER
> @@ -72,6 +74,7 @@ config SOC_AM43XX
> depends on ARCH_MULTI_V7
> select CPU_V7
> select ARCH_OMAP2PLUS
> + select ARCH_HAS_OPP
> select MULTI_IRQ_HANDLER
> select ARM_GIC
> select MACH_OMAP_GENERIC
> @@ -80,6 +83,7 @@ config SOC_DRA7XX
> bool "TI DRA7XX"
> depends on ARCH_MULTI_V7
> select ARCH_OMAP2PLUS
> + select ARCH_HAS_OPP
> select ARM_CPU_SUSPEND if PM
> select ARM_GIC
> select CPU_V7
>
--
Regards,
Nishanth Menon
^ permalink raw reply
* [PATCH v3 1/3] ARM: sun7i/sun6i: irqchip: Add irqchip driver for NMI controller
From: Carlo Caione @ 2014-01-29 13:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140129125818.GO3867@lukather>
On Wed, Jan 29, 2014 at 1:58 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
>
> So, to sum things up, what you see is something like:
>
> handle_level_irq
> | device device
> | mask ack handler irq acked unmask
> | | | | | |
> v v v v v v
>
> NMI -> GIC:
> +--------+ +---------------------
> ---------------+ +-----+
>
> PMIC -> NMI:
> +-------------------------+
> ------------+ +-------------
>
> And you get a "rogue" retrigger because the NMI -> GIC level went up
> again.
I'd say something like:
handle_level_irq
| device device
| mask ack handler irq acked unmask
| | | | | |
v v v v v v
NMI -> GIC:
+-----------------------------+
---------------+ +------
PMIC -> NMI:
+-------------------------+
------------+ +-------------
> I'm not exactly sure on how to fix this. Maybe by adding a call to the
> irqchip's ack just before the unmask in irq_finalize_oneshot?
That is exactly what the unmask callback in the NMI controller driver does.
The unmask_irq() in irq_finalize_oneshot() calls the unmask callback
in the driver (sunxi_sc_nmi_ack_and_unmask()) that ACKs the line
before unmasking it again.
Best,
--
Carlo Caione
^ permalink raw reply
* PCIe trouble on imx6q
From: Bjorn Helgaas @ 2014-01-29 12:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAM9uW_56VQTui7ggin2kCHH=5JfS2SCm--T51azUZA3da8st9g@mail.gmail.com>
[+cc linux-arm, Richard, Shawn (please keep the cc list)]
On Wed, Jan 29, 2014 at 2:28 AM, Kamel BOUHARA <k.bouhara@gmail.com> wrote:
> ---------- Forwarded message ----------
> From: Kamel BOUHARA <k.bouhara@gmail.com>
> Date: 2014-01-29
> Subject: Re: PCIe trouble on imx6q
> To: Bjorn Helgaas <bhelgaas@google.com>
>
>
> 2014-01-28 Bjorn Helgaas <bhelgaas@google.com>:
>> [+cc Richard, Shawn, linux-arm-kernel (all from MAINTAINERS)]
>>
>> On Tue, Jan 28, 2014 at 1:02 AM, Kamel BOUHARA <k.bouhara@gmail.com> wrote:
>>> Hello,
>>>
>>> Im getting trouble with kernel 3.13 at boot time, the pcie link failed
>>> to get up with the following log:
>>> ------------[ cut here ]------------
>>> WARNING: CPU: 0 PID: 1 at drivers/gpio/gpiolib.c:159 gpio_to_desc+0x34/0x48()
>>> invalid GPIO -2
>>> Modules linked in:
>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.13.0+ #4
>>> Backtrace:
>>> [<8001217c>] (dump_backtrace) from [<80012460>] (show_stack+0x18/0x1c)
>>> r6:802b9548 r5:00000000 r4:808d3060 r3:00000000
>>> [<80012448>] (show_stack) from [<806414fc>] (dump_stack+0x84/0x9c)
>>> [<80641478>] (dump_stack) from [<800289f8>] (warn_slowpath_common+0x70/0x94)
>>> r5:00000009 r4:bf05bcb0
>>> [<80028988>] (warn_slowpath_common) from [<80028a54>]
>>> (warn_slowpath_fmt+0x38/0x40)
>>> r8:01f00000 r7:00000000 r6:0011cc11 r5:808b68c0 r4:bf24fa30
>>> [<80028a20>] (warn_slowpath_fmt) from [<802b9548>] (gpio_to_desc+0x34/0x48)
>>> r3:fffffffe r2:807d23fc
>>> [<802b9514>] (gpio_to_desc) from [<802d9de0>] (imx6_pcie_host_init+0x174/0x434)
>>> [<802d9c6c>] (imx6_pcie_host_init) from [<80886dbc>]
>>> (dw_pcie_host_init+0x348/0x41c)
>>> r6:00000000 r5:808d52cc r4:00000020 r3:802d9c6c
>>> [<80886a74>] (dw_pcie_host_init) from [<808871d4>] (imx6_pcie_probe+0x320/0x3dc)
>>> r10:00000000 r9:000000c4 r8:808d539c r7:bf7e3384 r6:bf24fa30 r5:bf135810
>>> r4:bf24fa10
>>> [<80886eb4>] (imx6_pcie_probe) from [<8034b670>] (platform_drv_probe+0x20/0x50)
>>> r8:808d539c r7:00000000 r6:00000000 r5:808d539c r4:bf135810
>>> [<8034b650>] (platform_drv_probe) from [<80349c74>]
>>> (driver_probe_device+0x118/0x234)
>>> r5:bf135810 r4:80e526b8
>>> [<80349b5c>] (driver_probe_device) from [<80349e78>] (__driver_attach+0x9c/0xa0)
>>> r8:80886e90 r7:00000000 r6:bf135844 r5:808d539c r4:bf135810 r3:00000000
>>> [<80349ddc>] (__driver_attach) from [<8034806c>] (bus_for_each_dev+0x68/0x9c)
>>> r6:80349ddc r5:808d539c r4:00000000 r3:00000000
>>> [<80348004>] (bus_for_each_dev) from [<8034972c>] (driver_attach+0x20/0x28)
>>> r6:808df6a8 r5:bf1f5e00 r4:808d539c
>>> [<8034970c>] (driver_attach) from [<803493b0>] (bus_add_driver+0x148/0x1f4)
>>> [<80349268>] (bus_add_driver) from [<8034a4c8>] (driver_register+0x80/0x100)
>>> r7:8090e640 r6:8090e640 r5:00000005 r4:808d539c
>>> [<8034a448>] (driver_register) from [<8034b63c>]
>>> (__platform_driver_register+0x50/0x64)
>>> r5:00000005 r4:808d5388
>>> [<8034b5ec>] (__platform_driver_register) from [<8034b6e0>]
>>> (platform_driver_probe+0x28/0xac)
>>> [<8034b6b8>] (platform_driver_probe) from [<80886ea8>]
>>> (imx6_pcie_init+0x18/0x24)
>>> r5:00000005 r4:808aa104
>>> [<80886e90>] (imx6_pcie_init) from [<80008978>] (do_one_initcall+0x100/0x164)
>>> [<80008878>] (do_one_initcall) from [<8085ecc0>]
>>> (kernel_init_freeable+0x10c/0x1d0)
>>> r10:8089e060 r9:000000c4 r8:8089e050 r7:8090e640 r6:8090e640 r5:00000005
>>> r4:808aa104
>>> [<8085ebb4>] (kernel_init_freeable) from [<8063b67c>] (kernel_init+0x10/0x120)
>>> r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:8063b66c
>>> r4:00000000
>>> [<8063b66c>] (kernel_init) from [<8000e9c8>] (ret_from_fork+0x14/0x2c)
>>> r4:00000000 r3:ffffffff
>>> ---[ end trace b5e746dfc2398cd6 ]---
>>> ------------[ cut here ]------------
>>> WARNING: CPU: 0 PID: 1 at drivers/gpio/gpiolib.c:159 gpio_to_desc+0x34/0x48()
>>> invalid GPIO -2
>>> Modules linked in:
>>> CPU: 0 PID: 1 Comm: swapper/0 Tainted: G W 3.13.0+ #4
>>> Backtrace:
>>> [<8001217c>] (dump_backtrace) from [<80012460>] (show_stack+0x18/0x1c)
>>> r6:802b9548 r5:00000000 r4:808d3060 r3:00000000
>>> [<80012448>] (show_stack) from [<806414fc>] (dump_stack+0x84/0x9c)
>>> [<80641478>] (dump_stack) from [<800289f8>] (warn_slowpath_common+0x70/0x94)
>>> r5:00000009 r4:bf05bcb0
>>> [<80028988>] (warn_slowpath_common) from [<80028a54>]
>>> (warn_slowpath_fmt+0x38/0x40)
>>> r8:01f00000 r7:00000000 r6:0011cc11 r5:808b68c0 r4:bf24fa30
>>> [<80028a20>] (warn_slowpath_fmt) from [<802b9548>] (gpio_to_desc+0x34/0x48)
>>> r3:fffffffe r2:807d23fc
>>> [<802b9514>] (gpio_to_desc) from [<802d9df8>] (imx6_pcie_host_init+0x18c/0x434)
>>> [<802d9c6c>] (imx6_pcie_host_init) from [<80886dbc>]
>>> (dw_pcie_host_init+0x348/0x41c)
>>> r6:00000000 r5:808d52cc r4:00000020 r3:802d9c6c
>>> [<80886a74>] (dw_pcie_host_init) from [<808871d4>] (imx6_pcie_probe+0x320/0x3dc)
>>> r10:00000000 r9:000000c4 r8:808d539c r7:bf7e3384 r6:bf24fa30 r5:bf135810
>>> r4:bf24fa10
>>> [<80886eb4>] (imx6_pcie_probe) from [<8034b670>] (platform_drv_probe+0x20/0x50)
>>> r8:808d539c r7:00000000 r6:00000000 r5:808d539c r4:bf135810
>>> [<8034b650>] (platform_drv_probe) from [<80349c74>]
>>> (driver_probe_device+0x118/0x234)
>>> r5:bf135810 r4:80e526b8
>>> [<80349b5c>] (driver_probe_device) from [<80349e78>] (__driver_attach+0x9c/0xa0)
>>> r8:80886e90 r7:00000000 r6:bf135844 r5:808d539c r4:bf135810 r3:00000000
>>> [<80349ddc>] (__driver_attach) from [<8034806c>] (bus_for_each_dev+0x68/0x9c)
>>> r6:80349ddc r5:808d539c r4:00000000 r3:00000000
>>> [<80348004>] (bus_for_each_dev) from [<8034972c>] (driver_attach+0x20/0x28)
>>> r6:808df6a8 r5:bf1f5e00 r4:808d539c
>>> [<8034970c>] (driver_attach) from [<803493b0>] (bus_add_driver+0x148/0x1f4)
>>> [<80349268>] (bus_add_driver) from [<8034a4c8>] (driver_register+0x80/0x100)
>>> r7:8090e640 r6:8090e640 r5:00000005 r4:808d539c
>>> [<8034a448>] (driver_register) from [<8034b63c>]
>>> (__platform_driver_register+0x50/0x64)
>>> r5:00000005 r4:808d5388
>>> [<8034b5ec>] (__platform_driver_register) from [<8034b6e0>]
>>> (platform_driver_probe+0x28/0xac)
>>> [<8034b6b8>] (platform_driver_probe) from [<80886ea8>]
>>> (imx6_pcie_init+0x18/0x24)
>>> r5:00000005 r4:808aa104
>>> [<80886e90>] (imx6_pcie_init) from [<80008978>] (do_one_initcall+0x100/0x164)
>>> [<80008878>] (do_one_initcall) from [<8085ecc0>]
>>> (kernel_init_freeable+0x10c/0x1d0)
>>> r10:8089e060 r9:000000c4 r8:8089e050 r7:8090e640 r6:8090e640 r5:00000005
>>> r4:808aa104
>>> [<8085ebb4>] (kernel_init_freeable) from [<8063b67c>] (kernel_init+0x10/0x120)
>>> r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:8063b66c
>>> r4:00000000
>>> [<8063b66c>] (kernel_init) from [<8000e9c8>] (ret_from_fork+0x14/0x2c)
>>> r4:00000000 r3:ffffffff
>>> ---[ end trace b5e746dfc2398cd7 ]---
>>> imx6q-pcie 1ffc000.pcie: phy link never came up
>>> PCI host bridge to bus 0000:00
>>> pci_bus 0000:00: root bus resource [io 0x1000-0x10000]
>>> pci_bus 0000:00: root bus resource [mem 0x01000000-0x01efffff]
>>> pci_bus 0000:00: No busn resource found for root bus, will use [bus 00-ff]
>>
>> Not related to the GPIO/link problem, but something's wrong here --
>> the host bridge driver should be telling us what bus numbers are
>> behind the host bridge. Since it didn't, the PCI core had to guess.
>>
>>> PCI: bus0: Fast back to back transfers disabled
>>> PCI: bus1: Fast back to back transfers enabled
>>> pci 0000:00:00.0: BAR 0: assigned [mem 0x01000000-0x010fffff]
>>> pci 0000:00:00.0: BAR 6: assigned [mem 0x01100000-0x0110ffff pref]
>>> pci 0000:00:00.0: PCI bridge to [bus 01]
>>> pci 0000:00:00.0: PCI bridge to [bus 01]
>>>
>>> Please, any help is welcome.
>>> Regards,
>>> Kamel.B
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
>>> the body of a message to majordomo at vger.kernel.org
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> So I suppose, this is not a hardware issue rather a bad configuration ?
> Maybe the following log from lspci will be helpful ?
It looks like a configuration issue or an imx6q host bridge issue. In
either case, it looks like something *before* we get to PCIe, so
something like your DT description of the host bridge is more likely
to be useful.
> root at phyFLEX-i:~ lspci -vvv
> 00:00.0 PCI bridge: Device 16c3:abcd (rev 01) (prog-if 00 [Normal decode])
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
> ParErr+ Stepping- SERR+ FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Region 0: Memory at 01000000 (32-bit, non-prefetchable) [size=1M]
> Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
> I/O behind bridge: 0000f000-00000fff
> Memory behind bridge: fff00000-000fffff
> Prefetchable memory behind bridge: fff00000-000fffff
> Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- <SERR- <PERR-
> [virtual] Expansion ROM at 01100000 [disabled] [size=64K]
> BridgeCtl: Parity+ SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
> PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
> Capabilities: [40] Power Management version 3
> Flags: PMEClk- DSI- D1+ D2- AuxCurrent=375mA
> PME(D0+,D1+,D2-,D3hot+,D3cold+)
> Status: D0 PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [50] MSI: Mask+ 64bit+ Count=1/1 Enable+
> Address: 0000000090000000 Data: 0000
> Masking: 00000000 Pending: 00000000
> Capabilities: [70] Express (v2) Root Port (Slot-), MSI 00
> DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s
> <64ns, L1 <1us
> ExtTag- RBE+ FLReset-
> DevCtl: Report errors: Correctable+ Non-Fatal+ Fatal+
> Unsupported+
> RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 512 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq-
> AuxPwr+ TransPend-
> LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1,
> Latency L0 <1us, L1 <8us
> ClockPM- Surprise- LLActRep+ BwNot-
> LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
> ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train-
> SlotClk+ DLActive- BWMgmt- ABWMgmt-
> RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal-
> PMEIntEna+ CRSVisible-
> RootCap: CRSVisible-
> RootSta: PME ReqID 0000, PMEStatus- PMEPending-
> DevCap2: Completion Timeout: Range ABCD, TimeoutDis+ ARIFwd-
> DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- ARIFwd-
> LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance-
> SpeedDis-, Selectable De-emphasis: -6dB
> Transmit Margin: Normal Operating Range,
> EnterModifiedCompliance- ComplianceSOS-
> Compliance De-emphasis: -6dB
> LnkSta2: Current De-emphasis Level: -3.5dB
> Capabilities: [100] Advanced Error Reporting
> UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt-
> UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
> UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt-
> UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
> UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt-
> UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
> CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr-
> CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
> AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
> Capabilities: [140] Virtual Channel <?>
> Kernel driver in use: pcieport
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" 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 v3 1/3] ARM: sun7i/sun6i: irqchip: Add irqchip driver for NMI controller
From: Maxime Ripard @ 2014-01-29 12:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOQ7t2YLv8dNF6i-X6Y1BgvvcBCNt6JhmpGuo23E057xez6+Tg@mail.gmail.com>
On Tue, Jan 28, 2014 at 10:02:46PM +0100, Carlo Caione wrote:
> Hi,
>
> On Tue, Jan 28, 2014 at 5:41 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Hi,
> >
> > On Tue, Jan 28, 2014 at 12:02:23PM +0100, Hans de Goede wrote:
> >> -----BEGIN PGP SIGNED MESSAGE-----
> >> Hash: SHA1
> >>
> >> Hi,
> >>
> >> On 01/28/2014 11:40 AM, Maxime Ripard wrote:
> >>
> >> Jumping in here to try and clarify things, or so I hope at least :)
> >
> > Sure :)
> >
> >> No, the IRQ from the PMIC is a level sensitive IRQ, so it would look
> >> like this:
> >
> > Hmm, your mailer seems to have mangled your drawing :(
> >
> >> The PMIC irq line won't go low until an i2c write to its irq status
> >> registers write-clears all status bits for which the corresponding
> >> bit in the irq-mask register is set.
> >
> > Which makes sense too
> >
> >> And the only reason the NMI -> GIC also goes low is because the unmask
> >> operation writes a second ack to the NMI controller in the unmask
> >> callback of the NMI controller driver.
> >
> > Yes, and this is exactly what I don't understand. You shouldn't need
> > that ack in first place, since it's been done already right after the
> > unmask.
>
> But the first ack is ignored since the IRQ line is still maintained
> asserted by PMIC.
>
> >> Note that we cannot use edge triggered interrupts here because the PMIC
> >> has the typical setup with multiple irq status bits driving a single
> >> irq line, so the irq handler does read irq-status, handle stuff,
> >> write-clear irq-status. And if any other irq-status bits get set
> >> between the read and write-clear the PMIC -> NMI line will stay
> >> high, as it should since there are more interrupts to handle.
> >
> > Yep, the edge-thing was just the only case I could think of where it
> > could lead to troubles.
> >
> > In what you're saying, which makes total sense, if we don't do the
> > ack, as soon as the irq will be unmasked, since the level is high, the
> > handler will be called again, treat the new interrupts, and so on. I
> > don't see how this is an issue actually.
>
> This is exactly why in unmask callback we first ACK and then unmask.
> So, if the line is still maintained up by PMIC then a new interrupt is
> raised otherwise nothing happens.
>
> >> > But in this case, you would have two events coming from your
> >> > device (the two rising edges), so you'd expect two interrupts. And
> >> > in the case of a level triggered interrupt, the device would keep
> >> > the interrupt line active until it's unmasked, so we wouldn't end
> >> > up with this either.
> >> >
> >> >> sunxi_sc_nmi_ack_and_unmask is therefore called (by
> >> >> irq_finalize_oneshot) after the IRQ thread has been
> >> >> executed. After the IRQ thread has ACKed the IRQs on the
> >> >> originating device we can finally ACK and unmask again the NMI.
> >> >
> >> > And what happens if you get a new interrupt right between the end
> >> > of the handler and the unmask?
> >>
> >> The implicit ack done by the unmask will be ignored if the NMI line
> >> is still high, just like the initial ack is ignored (which is why we
> >> need the mask), and when the unmask completes the irq will
> >> immediately retrigger, as it should.
> >
> > Yeah, but why do we need the ack in the first place? I can't think of
> > a case where the ACK would be doing something useful. Either:
> > - there is no new interrupts between the mask/ack and the unmask, so
> > there's no interrupt to ack.
> > - There's a new interrupt between the mask/ack and the
> > unmask. There's two more cases here:
> > * The interrupt came before the device handler kicked in, and the
> > handler will treat it/ack it: No issue
> > * The interrupt comes right after the handler has been acking its
> > interrupt, the level stays high, your handler is called once
> > again, you can treat it: No issue
>
> AFAIU the problem here is that the only ACK that is able to assert the
> line NMI -> GIC is the ACK by the unmask callback. All the others ACKs
> before that one are ignored by the NMI controller since the line PMIC
> -> NMI is still asserted.
So, to sum things up, what you see is something like:
handle_level_irq
| device device
| mask ack handler irq acked unmask
| | | | | |
v v v v v v
NMI -> GIC:
+--------+ +---------------------
---------------+ +-----+
PMIC -> NMI:
+-------------------------+
------------+ +-------------
And you get a "rogue" retrigger because the NMI -> GIC level went up
again.
I'm not exactly sure on how to fix this. Maybe by adding a call to the
irqchip's ack just before the unmask in irq_finalize_oneshot?
Thomas, what are your thoughts on this?
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140129/f5612997/attachment.sig>
^ permalink raw reply
* [PATCH] ARM: iop32x: fix reset handling for the EM7210 board
From: Arnaud Patard (Rtp) @ 2014-01-29 12:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390999545-31428-1-git-send-email-linus.walleij@linaro.org>
Linus Walleij <linus.walleij@linaro.org> writes:
Hi,
don't know how to comment about the subjet but it's _not_ about
resetting the board but about powering it off.
> This board was missed when converting all the others to proper
> abstracted GPIO handling. Fix it up the right way by requesting
> and driving GPIO line 0 high through gpiolib to reset the machine.
>
> Reported-by: Arnd Bergmann <arnd@arndb.de>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> ARM SoC folks, if you're happy with this fix, please apply it
> directly to fixes in the ARM SoC tree.
> ---
> arch/arm/mach-iop32x/em7210.c | 16 +++++++++++++---
> 1 file changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c
> index 177cd073a83b..e0c4187f3799 100644
> --- a/arch/arm/mach-iop32x/em7210.c
> +++ b/arch/arm/mach-iop32x/em7210.c
> @@ -23,6 +23,7 @@
> #include <linux/mtd/physmap.h>
> #include <linux/platform_device.h>
> #include <linux/i2c.h>
> +#include <linux/gpio.h>
> #include <mach/hardware.h>
> #include <linux/io.h>
> #include <linux/irq.h>
> @@ -176,14 +177,21 @@ static struct platform_device em7210_serial_device = {
> .resource = &em7210_uart_resource,
> };
>
> +#define EM7210_HARDWARE_RESET 0
> +
please fix accoring to my previous comment.
> void em7210_power_off(void)
> {
> - *IOP3XX_GPOE &= 0xfe;
> - *IOP3XX_GPOD |= 0x01;
> + int ret;
> +
> + ret = gpio_direction_output(EM7210_HARDWARE_RESET, 1);
> + if (ret)
> + pr_crit("could not drive reset GPIO high\n");
> }
>
> static void __init em7210_init_machine(void)
> {
> + int ret;
> +
> register_iop32x_gpio();
> platform_device_register(&em7210_serial_device);
> platform_device_register(&iop3xx_i2c0_device);
> @@ -194,7 +202,9 @@ static void __init em7210_init_machine(void)
>
> i2c_register_board_info(0, em7210_i2c_devices,
> ARRAY_SIZE(em7210_i2c_devices));
> -
> + ret = gpio_request(EM7210_HARDWARE_RESET, "reset");
> + if (ret)
> + pr_err("could not request reset GPIO\n");
no chance to work. too early. you'll get a -EPROBE_DEFER.
Arnaud
^ permalink raw reply
* [PATCH] ARM: iop32x: fix reset handling for the EM7210 board
From: Linus Walleij @ 2014-01-29 12:45 UTC (permalink / raw)
To: linux-arm-kernel
This board was missed when converting all the others to proper
abstracted GPIO handling. Fix it up the right way by requesting
and driving GPIO line 0 high through gpiolib to reset the machine.
Reported-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ARM SoC folks, if you're happy with this fix, please apply it
directly to fixes in the ARM SoC tree.
---
arch/arm/mach-iop32x/em7210.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c
index 177cd073a83b..e0c4187f3799 100644
--- a/arch/arm/mach-iop32x/em7210.c
+++ b/arch/arm/mach-iop32x/em7210.c
@@ -23,6 +23,7 @@
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/gpio.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -176,14 +177,21 @@ static struct platform_device em7210_serial_device = {
.resource = &em7210_uart_resource,
};
+#define EM7210_HARDWARE_RESET 0
+
void em7210_power_off(void)
{
- *IOP3XX_GPOE &= 0xfe;
- *IOP3XX_GPOD |= 0x01;
+ int ret;
+
+ ret = gpio_direction_output(EM7210_HARDWARE_RESET, 1);
+ if (ret)
+ pr_crit("could not drive reset GPIO high\n");
}
static void __init em7210_init_machine(void)
{
+ int ret;
+
register_iop32x_gpio();
platform_device_register(&em7210_serial_device);
platform_device_register(&iop3xx_i2c0_device);
@@ -194,7 +202,9 @@ static void __init em7210_init_machine(void)
i2c_register_board_info(0, em7210_i2c_devices,
ARRAY_SIZE(em7210_i2c_devices));
-
+ ret = gpio_request(EM7210_HARDWARE_RESET, "reset");
+ if (ret)
+ pr_err("could not request reset GPIO\n");
pm_power_off = em7210_power_off;
}
--
1.8.5.3
^ permalink raw reply related
* iop32x: gpio breakage after "instantiate GPIO from platform device"
From: Arnd Bergmann @ 2014-01-29 12:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACRpkdbd1FOOZOrF5crh3dYfYOy1CaYFH-SOqw_SJmd39JBjhg@mail.gmail.com>
On Wednesday 29 January 2014 13:41:59 Linus Walleij wrote:
> On Tue, Jan 28, 2014 at 10:05 PM, Arnd Bergmann <arnd@arndb.de> wrote:
>
> > Commit 7b85b867b9904 "ARM: plat-iop: instantiate GPIO from platform
> > device" nicely cleaned up the gpio register access for iop, but
> > forgot one board that directly pokes into the gpio registers
> > to do a system reset.
> >
> > That board no longer compiles, and this patch just disables
> > the code in question to work around it so I can locally build
> > randconfig again, but it needs to be fixed properly.
>
> OK I'm sending a proper fix instead.
Ok, thanks!
Arnd
^ permalink raw reply
* [PATCH RFC v2 2/2] Documentation: arm: define DT C-states bindings
From: Lorenzo Pieralisi @ 2014-01-29 12:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKfTPtAEekg_KHhLikJK=njC-b5F=MOmAmSP8P96+j_23-iu3Q@mail.gmail.com>
On Tue, Jan 28, 2014 at 08:24:54AM +0000, Vincent Guittot wrote:
> On 24 January 2014 18:58, Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> wrote:
[...]
> >> Please look below, i have modified the rest of your example accordingly
> >>
> >> >
> >> > }:
> >> >
> >> > and then
> >> >
> >> > state0 {
> >> > index = <2>;
> >> > compatible = "arm,cpu-power-state";
> >> > latency = <...>;
> >> > /*
> >> > * This means that when the state is entered, the power
> >> > * controller should use register index 0 and state 0,
> >> > * whose meaning is power controller specific. Since we
> >> > * know all components affected (for every component
> >> > * we declare its power domain(s) and states so we
> >> > * know what components are affected by the state entry.
> >> > * Given the cache node above and this phandle, the state
> >> > * implies that the cache is retained, register index == 0 state == 0
> >> > /*
> >> > power-domain =<&foo_power_controller 0 0>;
> >>
> >> for retention state we need to set the power domain in state 1
> >> power-domain =<&foo_power_controller 0 1>;
> >>
> >> > };
> >> >
> >> > state1 {
> >> > index = <3>;
> >> > compatible = "arm,cpu-power-state";
> >> > latency = <...>;
> >> > /*
> >> > * This means that when the state is entered, the power
> >> > * controller should use register index 0 and state 1,
> >> > * whose meaning is power controller specific. Since we
> >> > * know all components affected (for every component
> >> > * we declare its power domain(s) and states so we
> >> > * know what components are affected by the state entry.
> >> > * Given the cache node above and this phandle, the state
> >> > * implies that the cache is lost, register index == 0 state == 1
> >> > /*
> >> > power-domain =<&foo_power_controller 0 1>;
> >>
> >> for power down mode, we need to set thge power domain in state 2
> >> power-domain =<&foo_power_controller 0 2>;
> >
> > Ok, what I meant was not what you got, but your approach looks sensible
> > too. What I do not like is that the power-domain specifier is power
>
> sorry for the misconception of your example
>
> > controller specific (that was true even for my example). In theory
> > we can achieve something identical by forcing every component in a power
> > domain to specify the max C-state index that allows it to retain its
>
> I'm not sure that we should force a component to set an opaque (for
> the component) max c-state. The device should describe its power
> domain requirements and the correlation of the latter with the
> description of the c-state binding should be enough to deduct the max
> c-state.
I agree, that was an option, I just loathe the idea of implementing it.
Using power domain specifiers is ways cleaner IMHO, the only drawback is
that, it is up to the power domain documentation to define what a state
means in terms of save/restore and cache behavior. I think that makes
perfect sense, at least for me.
> > state (through a specific property). Same logic to your example applies.
> > Nice thing is that we do not change the power domain specifiers, bad thing
> > is that it adds two properties to each device (c-state index and
> > power-domain-specifier - but we can make it hierarchical so that device
> > nodes can inherit the maximum operating C-state by inheriting the value
> > from a parent node providing a common value).
> >
> > In my example the third parameter was just a number that the power
> > controller would decode (eg 0 = cache retained, 1 = cache lost)
> > according to its implementation, it was not a "state index". The
> > power controller would know what to do with eg a cache component (that
> > declares to be in that power domain) when a C-state with that power
> > domain specifier was entered.
> >
> > Not very different from what you are saying, let's get to the nub:
> >
> > - Either we define it in a platform specific way through the power
> > domain specifier
> > - Or we force a max-c-state-supported property for every device,
> > possibly hierarchical
>
> As explained above, adding a max-cstate property for a device that
> only know the power-domain is not a good thing IMHO.
I agree, if nobody complains that's the way I will define the bindings.
Thank you,
Lorenzo
^ permalink raw reply
* iop32x: gpio breakage after "instantiate GPIO from platform device"
From: Linus Walleij @ 2014-01-29 12:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4202760.m9CxkiIWk3@wuerfel>
On Tue, Jan 28, 2014 at 10:05 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> Commit 7b85b867b9904 "ARM: plat-iop: instantiate GPIO from platform
> device" nicely cleaned up the gpio register access for iop, but
> forgot one board that directly pokes into the gpio registers
> to do a system reset.
>
> That board no longer compiles, and this patch just disables
> the code in question to work around it so I can locally build
> randconfig again, but it needs to be fixed properly.
OK I'm sending a proper fix instead.
Yours,
Linus Walleij
^ permalink raw reply
* Building with gcc 4.6.4
From: Mikael Pettersson @ 2014-01-29 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140128150611.GL15937@n2100.arm.linux.org.uk>
Russell King - ARM Linux writes:
> On Tue, Jan 28, 2014 at 03:38:14PM +0100, Mikael Pettersson wrote:
> > Russell King - ARM Linux writes:
> > > So, yesterday I built gcc 4.6.4 (mainline) for the autobuilder, and the
> > > result is that every build failed with the same error:
> > >
> > > scripts/mod/empty.c:1:0: error: FPA is unsupported in the AAPCS
> > >
> > > This seems to be because linux-elf targets default to fpe3 in mainline
> > > gcc, but specifying -mabi=aapcs-linux switches us into EABI mode where
> > > the compiler errors out with the default FPU.
> > >
> > > Hence, I believe we need this to ensure that a compatible VFP is
> > > selected. One can argue that building EABI ARMv4 with VFP is silly,
> > > but it seems that's what the gcc folk have decided (rightly or
> > > wrongly.)
> > >
> > > Maybe this is a bug in mainline GCC - which begs the question why
> > > (presumably, since no one has picked this up) Linaro's toolchain
> > > has fixes but mainline GCC doesn't.
> > >
> > > Comments?
> >
> > Perhaps because most ARM EABI toolchains default to soft-float,
> > and the hardfloat ones usually select v6 or v7 + vfp-d16 or neon
> > as their defaults, so the archaic FPA is never the default.
>
> soft-float has nothing to do with it, because the kernel always passes
> -msoft-float.
>
> > Or are you using an OABI toolchain to compile an EABI kernel?
>
> ... which should make no difference what so ever since the kernel should
> be passing the appropriate options. That's why we pass -mabi=aapcs-linux
> to the kernel.
I can reproduce your error with an OABI toolchain (gcc-4.6.4 or 4.7.3,
default configuration options wrt ISA and floating-point model), but
there's no such error with an EABI toolchain. So it looks like you've
found a GCC bug.
However, the toolchain people considers OABI to be obsolete, it's
unsupported since gcc-4.7.0, gcc-4.6 is EOL, and even gcc-4.7 is
nearing EOL (will probably happen this spring or early summer after
the release of gcc-4.9.0), so I doubt anyone is going to work on
this issue.
/Mikael
^ permalink raw reply
* [PATCH RFC v2 2/2] Documentation: arm: define DT C-states bindings
From: Lorenzo Pieralisi @ 2014-01-29 12:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140127155924.GA2178@e103592.cambridge.arm.com>
On Mon, Jan 27, 2014 at 03:59:37PM +0000, Dave Martin wrote:
> On Fri, Jan 24, 2014 at 05:58:07PM +0000, Lorenzo Pieralisi wrote:
[...]
> > > > state0 {
> > > > index = <2>;
> > > > compatible = "arm,cpu-power-state";
> > > > latency = <...>;
> > > > /*
> > > > * This means that when the state is entered, the power
> > > > * controller should use register index 0 and state 0,
> > > > * whose meaning is power controller specific. Since we
> > > > * know all components affected (for every component
> > > > * we declare its power domain(s) and states so we
> > > > * know what components are affected by the state entry.
> > > > * Given the cache node above and this phandle, the state
> > > > * implies that the cache is retained, register index == 0 state == 0
> > > > /*
> > > > power-domain =<&foo_power_controller 0 0>;
> > >
> > > for retention state we need to set the power domain in state 1
> > > power-domain =<&foo_power_controller 0 1>;
>
> The name "power-domain" probably needs changing if the specifier contains
> state information too.
>
> Instead, we could call it "power-state" or similar.
>
>
> Key issues I see:
>
> 1) How to describe platforms where there is no "power controller" as such,
> just a bunch of clocks and regulators that Linux has to poke directly.
>
> 2) Two devices might have the same power controller (in terms of IP and
> revision), but integrated in different ways. So, maybe thinking of
> the referenced thing as a power controller is not correct. We can
> thing in terms of referring to individual power domains, or maybe
> to a "power model" for the SoC.
The example was misleading. There is no link to a power controller as
such, the phandle is to a power domain, which fits with what you are
saying, basically the C-state does not care about how the power domain
is implemented, it just defines that that specific power domain is
affected. I am not sure we should change the naming either, a C-state
defines a power-domain specifier, which implies a certain behaviour
for a power domain. It is platform specific, so for certain platforms
the cells represent a state for others they do not.
> The power domain or model becomes a container for power (domains and)
> states, and refers to the IP blocks (power controllers, regulators,
> clocks, clamps, whatever) required to implement it.
>
> This change of abstraction might map more naturally onto "bunch
> of clocks and regulators" situations: the power model or domain
> binding can make symbolic references to clocks and regulators etc.,
> so that the binding becomes less dependent on the exact content of
> the rest of the DT.
Exactly, I agree, the complexity is in the power-domain (how states are
handled, what components should be programmed, etc) the C-state just
defines what power-domain it affects, with power domain specifier cells
providing additional, power domain specific, semantics (ie retention vs.
shutdown).
> 3) We need to be very clear that the power state specifier needs to be
> defined in terms of the actual hardware effects in the relevant SoC-
> specific binding -- at the "what" level, rather than "how".
>
> There's a fair chance of people getting lazy: they'll just stuff
> indices in the DT which map to random LUTs in the Linux driver. In
> that case, the DT would be describing the Linux driver, not the
> hardware -- that's not what we want.
>
> Delegating the job of defining power states to the SoC documentation
> seems acceptable, though.
I agree, and I think we are pretty close to a general agreement on this
specific subject.
Thank you,
Lorenzo
^ permalink raw reply
* [PATCH] arm: Add Arm Erratum 773769 for Large data RAM latency.
From: Sander @ 2014-01-29 12:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAD=FV=XqoSGpQ_Yrjj4hvV_0FSMfQGcGEsKkL1Stnm9m5s2Xvw@mail.gmail.com>
Doug Anderson wrote (ao):
> On Wed, Jan 8, 2014 at 1:08 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
> > On Wed, 8 Jan 2014, Doug Anderson wrote:
> >> * If Joe Upstream wants to run an upstream kernel on some type of
> >> exynos5250 product (Samsung ARM Chromebook, HP Chromebook 11, Nexus 10
> >> are the ones I know of) then he will deal with the small number of
> >> crashes or figure out a solution.
> >
> > If Joe Upstream wants to run an upstream kernel, doesn't he have to
> > unscrew his write protect switch first, at which point the RO firmware
> > can be updated as well?
>
> Actually, no. You can move your device into dev mode and run any
> kernel you want. You'll get an annoying "you're in dev mode" screen
> at every bootup, but otherwise it works just fine.
>
> Going into dev mode requires some special keystrokes at bootup and a
> wipe of your hard disk but no screwdrivers.
And there is http://www.arndaleboard.org/ where you just put an upstream
kernel on sd and boot.
Sander
^ permalink raw reply
* [PATCH v2 3/5] spi: sunxi: Add Allwinner A31 SPI controller driver
From: Mark Brown @ 2014-01-29 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390993850-9054-4-git-send-email-maxime.ripard@free-electrons.com>
On Wed, Jan 29, 2014 at 12:10:48PM +0100, Maxime Ripard wrote:
> +config SPI_SUN6I
> + tristate "Allwinner A31 SPI controller"
> + depends on ARCH_SUNXI || COMPILE_TEST
> + select PM_RUNTIME
> + help
> + This enables using the SPI controller on the Allwinner A31 SoCs.
> +
A select of PM_RUNTIME is both surprising and odd - why is that there?
The usual idiom is that the device starts out powered up (flagged using
pm_runtime_set_active()) and then runtime PM then suspends it when it's
compiled in. That way if for some reason people want to avoid runtime
PM they can still use the device.
> +static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
> +{
> + struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
> + u32 reg;
> +
> + if (!enable)
> + return;
> +
> + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
> + reg &= ~SUN6I_TFR_CTL_CS_MASK;
> + reg |= SUN6I_TFR_CTL_CS(spi->chip_select);
> + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
> +}
The !enable means that it'll only ever be able to go one way. Also note
that the documentation was clarified here to make the enable flag be the
absolute logic level, not if chip select was asserted.
> + timeout = wait_for_completion_timeout(&sspi->done,
> + msecs_to_jiffies(1000));
> + if (!timeout) {
> + ret = -ETIMEDOUT;
> + goto out;
> + }
> +
> + sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
This means we can only transfer a single FIFO of data? I didn't see a
check on the transfer length.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140129/34ca1e5b/attachment.sig>
^ permalink raw reply
* [PATCH] ARM: sa1100: fix compile problem on Collie
From: Linus Walleij @ 2014-01-29 12:23 UTC (permalink / raw)
To: linux-arm-kernel
Due to a problem in the MFD Kconfig it was not possible to
compile the UCB battery driver for the Collie SA1100 system,
in turn making it impossible to compile in the battery driver.
(See patch "mfd: include all drivers in subsystem menu".)
After fixing the MFD Kconfig (separate patch) a compile error
appears in the Collie battery driver due to the <mach/collie.h>
implicitly requiring <mach/hardware.h> through <linux/gpio.h>
via <mach/gpio.h> prior to commit
40ca061b "ARM: 7841/1: sa1100: remove complex GPIO interface".
Fix this up by including the required header into
<mach/collie.h>.
Cc: stable at vger.kernel.org
Cc: Andrea Adami <andrea.adami@gmail.com>
Cc: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
arch/arm/mach-sa1100/include/mach/collie.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h
index f33679d2d3ee..50e1d850ee2e 100644
--- a/arch/arm/mach-sa1100/include/mach/collie.h
+++ b/arch/arm/mach-sa1100/include/mach/collie.h
@@ -13,6 +13,8 @@
#ifndef __ASM_ARCH_COLLIE_H
#define __ASM_ARCH_COLLIE_H
+#include "hardware.h" /* Gives GPIO_MAX */
+
extern void locomolcd_power(int on);
#define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1)
--
1.8.5.3
^ permalink raw reply related
* [PATCH v2] ARM: dts: imx6qdl-sabreauto: Add PFUZE100 support
From: Fabio Estevam @ 2014-01-29 12:15 UTC (permalink / raw)
To: linux-arm-kernel
From: Fabio Estevam <fabio.estevam@freescale.com>
mx6 sabreauto boards have Freescale PFUZE100 regulator, so add support for it.
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
Changes since v1:
- Remove pingrp
arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 113 +++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)
diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index 10a00e4..772c5a1 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -63,6 +63,112 @@
status = "okay";
};
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+
+ pmic: pfuze100 at 08 {
+ compatible = "fsl,pfuze100";
+ reg = <0x08>;
+
+ regulators {
+ sw1a_reg: sw1ab {
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ sw1c_reg: sw1c {
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ sw2_reg: sw2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3a_reg: sw3a {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3b_reg: sw3b {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw4_reg: sw4 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ swbst_reg: swbst {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5150000>;
+ };
+
+ snvs_reg: vsnvs {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vref_reg: vrefddr {
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vgen1_reg: vgen1 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen2_reg: vgen2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen3_reg: vgen3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vgen4_reg: vgen4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen5_reg: vgen5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen6_reg: vgen6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;
@@ -111,6 +217,13 @@
>;
};
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
pinctrl_gpmi_nand: gpminandgrp {
fsl,pins = <
MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1
--
1.8.1.2
^ permalink raw reply related
* [PATCH v2 2/2] ARM: dts: imx6sl-evk: Add audio support
From: Fabio Estevam @ 2014-01-29 11:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390996695-25164-1-git-send-email-festevam@gmail.com>
From: Fabio Estevam <fabio.estevam@freescale.com>
imx6sl-evk has a wm8962 codec. Add support for it.
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
Changes since v1:
- Remove pingrp
- Use regulator at num mode
arch/arm/boot/dts/imx6sl-evk.dts | 81 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 4fc62e8..17db01a 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -43,9 +43,47 @@
gpio = <&gpio4 2 0>;
enable-active-high;
};
+
+ reg_aud3v: regulator at 2 {
+ compatible = "regulator-fixed";
+ regulator-name = "wm8962-supply-3v15";
+ regulator-min-microvolt = <3150000>;
+ regulator-max-microvolt = <3150000>;
+ regulator-boot-on;
+ };
+
+ reg_aud4v: regulator at 3 {
+ compatible = "regulator-fixed";
+ regulator-name = "wm8962-supply-4v2";
+ regulator-min-microvolt = <4325000>;
+ regulator-max-microvolt = <4325000>;
+ regulator-boot-on;
+ };
+ };
+
+ sound {
+ compatible = "fsl,imx6sl-evk-wm8962", "fsl,imx-audio-wm8962";
+ model = "wm8962-audio";
+ ssi-controller = <&ssi2>;
+ audio-codec = <&codec>;
+ audio-routing =
+ "Headphone Jack", "HPOUTL",
+ "Headphone Jack", "HPOUTR",
+ "Ext Spk", "SPKOUTL",
+ "Ext Spk", "SPKOUTR",
+ "AMIC", "MICBIAS",
+ "IN3R", "AMIC";
+ mux-int-port = <2>;
+ mux-ext-port = <3>;
};
};
+&audmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_audmux3>;
+ status = "okay";
+};
+
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
@@ -152,6 +190,27 @@
};
};
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+
+ codec: wm8962 at 1a {
+ compatible = "wlf,wm8962";
+ reg = <0x1a>;
+ clocks = <&clks IMX6SL_CLK_EXTERN_AUDIO>;
+ DCVDD-supply = <&vgen3_reg>;
+ DBVDD-supply = <®_aud3v>;
+ AVDD-supply = <&vgen3_reg>;
+ CPVDD-supply = <&vgen3_reg>;
+ MICVDD-supply = <®_aud3v>;
+ PLLVDD-supply = <&vgen3_reg>;
+ SPKVDD1-supply = <®_aud4v>;
+ SPKVDD2-supply = <®_aud4v>;
+ };
+};
+
&ecspi1 {
fsl,spi-num-chipselects = <1>;
cs-gpios = <&gpio4 11 0>;
@@ -189,6 +248,16 @@
MX6SL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059
MX6SL_PAD_KEY_COL4__GPIO4_IO00 0x80000000
MX6SL_PAD_KEY_COL5__GPIO4_IO02 0x80000000
+ MX6SL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130b0
+ >;
+ };
+
+ pinctrl_audmux3: audmux3grp {
+ fsl,pins = <
+ MX6SL_PAD_AUD_RXD__AUD3_RXD 0x4130b0
+ MX6SL_PAD_AUD_TXC__AUD3_TXC 0x4130b0
+ MX6SL_PAD_AUD_TXD__AUD3_TXD 0x4110b0
+ MX6SL_PAD_AUD_TXFS__AUD3_TXFS 0x4130b0
>;
};
@@ -199,6 +268,13 @@
>;
};
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x4001b8b1
+ MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
pinctrl_ecspi1: ecspi1grp {
fsl,pins = <
MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1
@@ -374,6 +450,11 @@
status = "okay";
};
+&ssi2 {
+ fsl,mode = "i2s-slave";
+ status = "okay";
+};
+
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
--
1.8.1.2
^ permalink raw reply related
* [PATCH v2 1/2] ARM: dts: imx6sl-evk: Add PFUZE100 support
From: Fabio Estevam @ 2014-01-29 11:58 UTC (permalink / raw)
To: linux-arm-kernel
From: Fabio Estevam <fabio.estevam@freescale.com>
imx6sl-evk board has Freescale PFUZE100 regulator, so add support for it.
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
Changes since v1:
- Remove pingrp
arch/arm/boot/dts/imx6sl-evk.dts | 113 +++++++++++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)
diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 0001804..4fc62e8 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -46,6 +46,112 @@
};
};
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ pmic: pfuze100 at 08 {
+ compatible = "fsl,pfuze100";
+ reg = <0x08>;
+
+ regulators {
+ sw1a_reg: sw1ab {
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ sw1c_reg: sw1c {
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ sw2_reg: sw2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3a_reg: sw3a {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3b_reg: sw3b {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw4_reg: sw4 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ swbst_reg: swbst {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5150000>;
+ };
+
+ snvs_reg: vsnvs {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vref_reg: vrefddr {
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vgen1_reg: vgen1 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen2_reg: vgen2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen3_reg: vgen3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vgen4_reg: vgen4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen5_reg: vgen5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen6_reg: vgen6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
&ecspi1 {
fsl,spi-num-chipselects = <1>;
cs-gpios = <&gpio4 11 0>;
@@ -86,6 +192,13 @@
>;
};
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1
+ MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1
+ >;
+ };
+
pinctrl_ecspi1: ecspi1grp {
fsl,pins = <
MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1
--
1.8.1.2
^ permalink raw reply related
* imx-drm: screen flickering
From: Sascha Hauer @ 2014-01-29 11:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAH9NwWe673znThNPWRvOCyAU2o7M-oouHD7+1tyRcmWTeJ8YFw@mail.gmail.com>
Hi Christian,
On Tue, Jan 28, 2014 at 09:11:32AM +0100, Christian Gmeiner wrote:
> Hi all.
>
> From time to time it happens that my LVDS display is flickering (look
> at scroll bar in the video).
> https://drive.google.com/file/d/0B_fznDimUHVubWtvVFlMTkdBbUU/edit?usp=sharing
>
> I really want to find the root cause of it, but I do not know where to
> start. I can trigger this
> sometimes after xscreensever "blanks" the screen and the screensafer
> gets disabled
> via user input.
>
> Any hints?
Sorry, no idea. Philipp and me watched the video, but we both haven't
seen something like this before.
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 5/5] ARM: sunxi: Enable A31 SPI and SID in the defconfig
From: Maxime Ripard @ 2014-01-29 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390993850-9054-1-git-send-email-maxime.ripard@free-electrons.com>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
arch/arm/configs/sunxi_defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index 3e2259b..b5df4a5 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -24,6 +24,7 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_EEPROM_SUNXI_SID=y
CONFIG_NETDEVICES=y
CONFIG_SUN4I_EMAC=y
# CONFIG_NET_CADENCE is not set
@@ -48,6 +49,8 @@ CONFIG_I2C=y
# CONFIG_I2C_COMPAT is not set
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MV64XXX=y
+CONFIG_SPI=y
+CONFIG_SPI_SUN6I=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
--
1.8.4.2
^ permalink raw reply related
* [PATCH v2 4/5] ARM: sun6i: dt: Add SPI controllers to the A31 DTSI
From: Maxime Ripard @ 2014-01-29 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390993850-9054-1-git-send-email-maxime.ripard@free-electrons.com>
The A31 has 4 SPI controllers. Add them in the DTSI.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
arch/arm/boot/dts/sun6i-a31.dtsi | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 0eea325..57af66f 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -340,6 +340,46 @@
status = "disabled";
};
+ spi0: spi at 01c68000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c68000 0x1000>;
+ interrupts = <0 65 4>;
+ clocks = <&ahb1_gates 20>, <&spi0_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 20>;
+ status = "disabled";
+ };
+
+ spi1: spi at 01c69000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c69000 0x1000>;
+ interrupts = <0 66 4>;
+ clocks = <&ahb1_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 21>;
+ status = "disabled";
+ };
+
+ spi2: spi at 01c6a000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c6a000 0x1000>;
+ interrupts = <0 67 4>;
+ clocks = <&ahb1_gates 22>, <&spi2_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 22>;
+ status = "disabled";
+ };
+
+ spi3: spi at 01c6b000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c6b000 0x1000>;
+ interrupts = <0 68 4>;
+ clocks = <&ahb1_gates 23>, <&spi3_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 23>;
+ status = "disabled";
+ };
+
gic: interrupt-controller at 01c81000 {
compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
reg = <0x01c81000 0x1000>,
--
1.8.4.2
^ permalink raw reply related
* [PATCH v2 3/5] spi: sunxi: Add Allwinner A31 SPI controller driver
From: Maxime Ripard @ 2014-01-29 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390993850-9054-1-git-send-email-maxime.ripard@free-electrons.com>
The Allwinner A31 has a new SPI controller IP compared to the older Allwinner
SoCs.
It supports DMA, but the driver only does PIO for now, and DMA will be
supported eventually.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
.../devicetree/bindings/spi/spi-sun6i.txt | 24 ++
drivers/spi/Kconfig | 7 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-sun6i.c | 478 +++++++++++++++++++++
4 files changed, 510 insertions(+)
create mode 100644 Documentation/devicetree/bindings/spi/spi-sun6i.txt
create mode 100644 drivers/spi/spi-sun6i.c
diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
new file mode 100644
index 0000000..21de73d
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
@@ -0,0 +1,24 @@
+Allwinner A31 SPI controller
+
+Required properties:
+- compatible: Should be "allwinner,sun6i-a31-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: phandle to the clocks feeding the SPI controller. Two are
+ needed:
+ - "ahb": the gated AHB parent clock
+ - "mod": the parent module clock
+- clock-names: Must contain the clock names described just above
+- resets: phandle to the reset controller asserting this device in
+ reset
+
+Example:
+
+spi1: spi at 01c69000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c69000 0x1000>;
+ interrupts = <0 66 4>;
+ clocks = <&ahb1_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 21>;
+};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index eb1f1ef..004e3b0 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -438,6 +438,13 @@ config SPI_SIRF
help
SPI driver for CSR SiRFprimaII SoCs
+config SPI_SUN6I
+ tristate "Allwinner A31 SPI controller"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ select PM_RUNTIME
+ help
+ This enables using the SPI controller on the Allwinner A31 SoCs.
+
config SPI_MXS
tristate "Freescale MXS SPI controller"
depends on ARCH_MXS
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index ab8d864..658ec64 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
+obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
new file mode 100644
index 0000000..32f3fc7
--- /dev/null
+++ b/drivers/spi/spi-sun6i.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#define SUN6I_FIFO_DEPTH 128
+
+#define SUN6I_GBL_CTL_REG 0x04
+#define SUN6I_GBL_CTL_BUS_ENABLE BIT(0)
+#define SUN6I_GBL_CTL_MASTER BIT(1)
+#define SUN6I_GBL_CTL_TP BIT(7)
+#define SUN6I_GBL_CTL_RST BIT(31)
+
+#define SUN6I_TFR_CTL_REG 0x08
+#define SUN6I_TFR_CTL_CPHA BIT(0)
+#define SUN6I_TFR_CTL_CPOL BIT(1)
+#define SUN6I_TFR_CTL_SPOL BIT(2)
+#define SUN6I_TFR_CTL_CS_MASK 0x3
+#define SUN6I_TFR_CTL_CS(cs) (((cs) & SUN6I_TFR_CTL_CS_MASK) << 4)
+#define SUN6I_TFR_CTL_DHB BIT(8)
+#define SUN6I_TFR_CTL_FBS BIT(12)
+#define SUN6I_TFR_CTL_XCH BIT(31)
+
+#define SUN6I_INT_CTL_REG 0x10
+#define SUN6I_INT_CTL_RF_OVF BIT(8)
+#define SUN6I_INT_CTL_TC BIT(12)
+
+#define SUN6I_INT_STA_REG 0x14
+
+#define SUN6I_FIFO_CTL_REG 0x18
+#define SUN6I_FIFO_CTL_RF_RST BIT(15)
+#define SUN6I_FIFO_CTL_TF_RST BIT(31)
+
+#define SUN6I_FIFO_STA_REG 0x1c
+#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
+#define SUN6I_FIFO_STA_RF_CNT_BITS 0
+#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f
+#define SUN6I_FIFO_STA_TF_CNT_BITS 16
+
+#define SUN6I_CLK_CTL_REG 0x24
+#define SUN6I_CLK_CTL_CDR2_MASK 0xff
+#define SUN6I_CLK_CTL_CDR2(div) (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0)
+#define SUN6I_CLK_CTL_CDR1_MASK 0xf
+#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN6I_CLK_CTL_DRS BIT(12)
+
+#define SUN6I_BURST_CNT_REG 0x30
+#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_XMIT_CNT_REG 0x34
+#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_BURST_CTL_CNT_REG 0x38
+#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_TXDATA_REG 0x200
+#define SUN6I_RXDATA_REG 0x300
+
+struct sun6i_spi {
+ struct spi_master *master;
+ void __iomem *base_addr;
+ struct clk *hclk;
+ struct clk *mclk;
+ struct reset_control *rstc;
+
+ struct completion done;
+
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+};
+
+static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
+{
+ return readl(sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
+{
+ writel(value, sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
+{
+ u32 reg, cnt;
+ u8 byte;
+
+ /* See how much data is available */
+ reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
+ reg &= SUN6I_FIFO_STA_RF_CNT_MASK;
+ cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS;
+
+ if (len > cnt)
+ len = cnt;
+
+ while (len--) {
+ byte = readb(sspi->base_addr + SUN6I_RXDATA_REG);
+ if (sspi->rx_buf)
+ *sspi->rx_buf++ = byte;
+ }
+}
+
+static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
+{
+ u8 byte;
+
+ if (len > sspi->len)
+ len = sspi->len;
+
+ while (len--) {
+ byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
+ writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG);
+ sspi->len--;
+ }
+}
+
+static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
+ u32 reg;
+
+ if (!enable)
+ return;
+
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+ reg &= ~SUN6I_TFR_CTL_CS_MASK;
+ reg |= SUN6I_TFR_CTL_CS(spi->chip_select);
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+}
+
+
+static int sun6i_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ unsigned int mclk_rate, div, timeout;
+ unsigned int tx_len = 0;
+ int ret = 0;
+ u32 reg;
+
+ /* We don't support transfer larger than the FIFO */
+ if (tfr->len > SUN6I_FIFO_DEPTH)
+ return -EINVAL;
+
+ reinit_completion(&sspi->done);
+ sspi->tx_buf = tfr->tx_buf;
+ sspi->rx_buf = tfr->rx_buf;
+ sspi->len = tfr->len;
+
+ /* Clear pending interrupts */
+ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
+
+ /* Reset FIFO */
+ sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
+ SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
+
+ /*
+ * Setup the transfer control register: Chip Select,
+ * polarities, etc.
+ */
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+
+ if (spi->mode & SPI_CPOL)
+ reg |= SUN6I_TFR_CTL_CPOL;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPOL;
+
+ if (spi->mode & SPI_CPHA)
+ reg |= SUN6I_TFR_CTL_CPHA;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPHA;
+
+ if (spi->mode & SPI_CS_HIGH)
+ reg &= ~SUN6I_TFR_CTL_SPOL;
+ else
+ reg |= SUN6I_TFR_CTL_SPOL;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= SUN6I_TFR_CTL_FBS;
+ else
+ reg &= ~SUN6I_TFR_CTL_FBS;
+
+ /*
+ * If it's a TX only transfer, we don't want to fill the RX
+ * FIFO with bogus data
+ */
+ if (sspi->rx_buf)
+ reg &= ~SUN6I_TFR_CTL_DHB;
+ else
+ reg |= SUN6I_TFR_CTL_DHB;
+
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
+ /* Ensure that we have a parent clock fast enough */
+ mclk_rate = clk_get_rate(sspi->mclk);
+ if (mclk_rate < (2 * spi->max_speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+ mclk_rate = clk_get_rate(sspi->mclk);
+ }
+
+ /*
+ * Setup clock divider.
+ *
+ * We have two choices there. Either we can use the clock
+ * divide rate 1, which is calculated thanks to this formula:
+ * SPI_CLK = MOD_CLK / (2 ^ cdr)
+ * Or we can use CDR2, which is calculated with the formula:
+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+ * Wether we use the former or the latter is set through the
+ * DRS bit.
+ *
+ * First try CDR2, and if we can't reach the expected
+ * frequency, fall back to CDR1.
+ */
+ div = mclk_rate / (2 * spi->max_speed_hz);
+ if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
+ if (div > 0)
+ div--;
+
+ reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;
+ } else {
+ div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+ reg = SUN6I_CLK_CTL_CDR1(div);
+ }
+
+ sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
+
+ /* Setup the transfer now... */
+ if (sspi->tx_buf)
+ tx_len = tfr->len;
+
+ /* Setup the counters */
+ sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len));
+ sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len));
+ sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG,
+ SUN6I_BURST_CTL_CNT_STC(tx_len));
+
+ /* Fill the TX FIFO */
+ sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+ /* Enable the interrupts */
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
+
+ /* Start the transfer */
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
+
+ timeout = wait_for_completion_timeout(&sspi->done,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+out:
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
+
+ return ret;
+}
+
+static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
+{
+ struct sun6i_spi *sspi = dev_id;
+ u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+
+ /* Transfer complete */
+ if (status & SUN6I_INT_CTL_TC) {
+ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
+ complete(&sspi->done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int sun6i_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(sspi->hclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable clock 'ahb spi'\n");
+ goto out;
+ }
+
+ ret = clk_prepare_enable(sspi->mclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable clock 'ahb spi'\n");
+ goto err;
+ }
+
+ ret = reset_control_deassert(sspi->rstc);
+ if (ret) {
+ dev_err(dev, "Couldn't deassert the device from reset\n");
+ goto err2;
+ }
+
+ sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
+ SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
+
+ return 0;
+
+err2:
+ clk_disable_unprepare(sspi->mclk);
+err:
+ clk_disable_unprepare(sspi->hclk);
+out:
+ return ret;
+}
+
+static int sun6i_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+ reset_control_assert(sspi->rstc);
+ clk_disable_unprepare(sspi->mclk);
+ clk_disable_unprepare(sspi->hclk);
+
+ return 0;
+}
+
+static int sun6i_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct sun6i_spi *sspi;
+ struct resource *res;
+ int ret = 0, irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
+ if (!master) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, master);
+ sspi = spi_master_get_devdata(master);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sspi->base_addr)) {
+ ret = PTR_ERR(sspi->base_addr);
+ goto err;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No spi IRQ specified\n");
+ ret = -ENXIO;
+ goto err;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
+ 0, "sun6i-spi", sspi);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request IRQ\n");
+ goto err;
+ }
+
+ sspi->master = master;
+ master->bus_num = -1;
+ master->set_cs = sun6i_spi_set_cs;
+ master->transfer_one = sun6i_spi_transfer_one;
+ master->num_chipselect = 4;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ /* Setup clocks */
+ sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(sspi->hclk)) {
+ dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
+ ret = PTR_ERR(sspi->hclk);
+ goto err;
+ }
+
+ sspi->mclk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(sspi->mclk)) {
+ dev_err(&pdev->dev, "Unable to acquire module clock\n");
+ ret = PTR_ERR(sspi->mclk);
+ goto err2;
+ }
+
+ init_completion(&sspi->done);
+
+ sspi->rstc = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(sspi->rstc)) {
+ dev_err(&pdev->dev, "Couldn't get reset controller\n");
+ ret = PTR_ERR(sspi->rstc);
+ goto err3;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = spi_register_master(master);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register SPI master\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ pm_runtime_disable(&pdev->dev);
+err3:
+ clk_disable_unprepare(sspi->mclk);
+err2:
+ clk_disable_unprepare(sspi->hclk);
+err:
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int sun6i_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+
+ spi_unregister_master(master);
+ pm_runtime_disable(&pdev->dev);
+ spi_master_put(master);
+
+ return 0;
+}
+
+static const struct of_device_id sun6i_spi_match[] = {
+ { .compatible = "allwinner,sun6i-a31-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun6i_spi_match);
+
+static const struct dev_pm_ops sun6i_spi_pm_ops = {
+ .runtime_resume = sun6i_spi_runtime_resume,
+ .runtime_suspend = sun6i_spi_runtime_suspend,
+};
+
+static struct platform_driver sun6i_spi_driver = {
+ .probe = sun6i_spi_probe,
+ .remove = sun6i_spi_remove,
+ .driver = {
+ .name = "sun6i-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_spi_match,
+ .pm = &sun6i_spi_pm_ops,
+ },
+};
+module_platform_driver(sun6i_spi_driver);
+
+MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 SPI controller driver");
+MODULE_LICENSE("GPL");
--
1.8.4.2
^ permalink raw reply related
* [PATCH v2 2/5] ARM: sun6i: dt: Add PLL6 and SPI module clocks
From: Maxime Ripard @ 2014-01-29 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390993850-9054-1-git-send-email-maxime.ripard@free-electrons.com>
The module clocks in the A31 are still compatible with the A10 one. Add the SPI
module clocks and the PLL6 in the device tree to allow their use by the SPI
controllers.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
arch/arm/boot/dts/sun6i-a31.dtsi | 46 ++++++++++++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 9 deletions(-)
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 5256ad9..0eea325 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -73,16 +73,12 @@
clocks = <&osc24M>;
};
- /*
- * This is a dummy clock, to be used as placeholder on
- * other mux clocks when a specific parent clock is not
- * yet implemented. It should be dropped when the driver
- * is complete.
- */
- pll6: pll6 {
+ pll6: clk at 01c20028 {
#clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <0>;
+ compatible = "allwinner,sun6i-a31-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6";
};
cpu: cpu at 01c20050 {
@@ -182,6 +178,38 @@
"apb2_uart1", "apb2_uart2", "apb2_uart3",
"apb2_uart4", "apb2_uart5";
};
+
+ spi0_clk: clk at 01c200a0 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-mod0-clk";
+ reg = <0x01c200a0 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi0";
+ };
+
+ spi1_clk: clk at 01c200a4 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-mod0-clk";
+ reg = <0x01c200a4 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi1";
+ };
+
+ spi2_clk: clk at 01c200a8 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-mod0-clk";
+ reg = <0x01c200a8 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi2";
+ };
+
+ spi3_clk: clk at 01c200ac {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-mod0-clk";
+ reg = <0x01c200ac 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi3";
+ };
};
soc at 01c00000 {
--
1.8.4.2
^ permalink raw reply related
* [PATCH v2 1/5] clk: sunxi: Add support for PLL6 on the A31
From: Maxime Ripard @ 2014-01-29 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390993850-9054-1-git-send-email-maxime.ripard@free-electrons.com>
The A31 has a slightly different PLL6 clock. Add support for this new clock in
our driver.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/clk-sunxi.c | 45 +++++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index c2cb762..954845c 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -11,6 +11,7 @@ Required properties:
"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
"allwinner,sun4i-pll5-clk" - for the PLL5 clock
"allwinner,sun4i-pll6-clk" - for the PLL6 clock
+ "allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
"allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
"allwinner,sun4i-axi-clk" - for the AXI clock
"allwinner,sun4i-axi-gates-clk" - for the AXI gates
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 659e4ea..990ad5d 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -249,7 +249,38 @@ static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate,
*n = DIV_ROUND_UP(div, (*k+1));
}
+/**
+ * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6
+ * PLL6 rate is calculated as follows
+ * rate = parent_rate * n * (k + 1) / 2
+ * parent_rate is always 24Mhz
+ */
+
+static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate,
+ u8 *n, u8 *k, u8 *m, u8 *p)
+{
+ u8 div;
+
+ /*
+ * We always have 24MHz / 2, so we can just say that our
+ * parent clock is 12MHz.
+ */
+ parent_rate = parent_rate / 2;
+
+ /* Normalize value to a parent_rate multiple (24M / 2) */
+ div = *freq / parent_rate;
+ *freq = parent_rate * div;
+
+ /* we were called to round the frequency, we can now return */
+ if (n == NULL)
+ return;
+
+ *k = div / 32;
+ if (*k > 3)
+ *k = 3;
+ *n = DIV_ROUND_UP(div, (*k+1));
+}
/**
* sun4i_get_apb1_factors() - calculates m, p factors for APB1
@@ -416,6 +447,13 @@ static struct clk_factors_config sun4i_pll5_config = {
.kwidth = 2,
};
+static struct clk_factors_config sun6i_a31_pll6_config = {
+ .nshift = 8,
+ .nwidth = 5,
+ .kshift = 4,
+ .kwidth = 2,
+};
+
static struct clk_factors_config sun4i_apb1_config = {
.mshift = 0,
.mwidth = 5,
@@ -457,6 +495,12 @@ static const struct factors_data sun4i_pll5_data __initconst = {
.getter = sun4i_get_pll5_factors,
};
+static const struct factors_data sun6i_a31_pll6_data __initconst = {
+ .enable = 31,
+ .table = &sun6i_a31_pll6_config,
+ .getter = sun6i_a31_get_pll6_factors,
+};
+
static const struct factors_data sun4i_apb1_data __initconst = {
.table = &sun4i_apb1_config,
.getter = sun4i_get_apb1_factors,
@@ -972,6 +1016,7 @@ free_clkdata:
static const struct of_device_id clk_factors_match[] __initconst = {
{.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
{.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
+ {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
{.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
{.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,},
{.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},
--
1.8.4.2
^ permalink raw reply related
* [PATCH v2 0/5] Add Allwinner A31 SPI controller support
From: Maxime Ripard @ 2014-01-29 11:10 UTC (permalink / raw)
To: linux-arm-kernel
Hi everyone,
This patchset brings support for the SPI controller found in the
Allwinner A31 SoC.
Even though the controller supports DMA, the driver only supports PIO
mode for now. This driver will be used to bring up and test DMA on the
SoC, so support for the DMA will come eventually.
It doesn't support transfer larger than the FIFO size (128 bytes) for
now, I expect it to be fixed in the future.
Thanks!
Maxime
Changes from v1:
- Switched to using the transfer_one and set_cs callbacks
- Switched to using runtime_pm
- Report an error when we try to do a transfer larger than the FIFO
size, instead of silently timeouting.
- Added a Kconfig symbol
- Move the clock ratio change at transfer time
- Fixed the PLL6 cell size in the DTSI
- A few fixes here and there: typos, etc.
Maxime Ripard (5):
clk: sunxi: Add support for PLL6 on the A31
ARM: sun6i: dt: Add PLL6 and SPI module clocks
spi: sunxi: Add Allwinner A31 SPI controller driver
ARM: sun6i: dt: Add SPI controllers to the A31 DTSI
ARM: sunxi: Enable A31 SPI and SID in the defconfig
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
.../devicetree/bindings/spi/spi-sun6i.txt | 24 ++
arch/arm/boot/dts/sun6i-a31.dtsi | 86 +++-
arch/arm/configs/sunxi_defconfig | 3 +
drivers/clk/sunxi/clk-sunxi.c | 45 ++
drivers/spi/Kconfig | 7 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-sun6i.c | 478 +++++++++++++++++++++
8 files changed, 636 insertions(+), 9 deletions(-)
create mode 100644 Documentation/devicetree/bindings/spi/spi-sun6i.txt
create mode 100644 drivers/spi/spi-sun6i.c
--
1.8.4.2
^ permalink raw reply
* [PATCH 11/11] arm: dma-mapping: Add support to extend DMA IOMMU mappings
From: Will Deacon @ 2014-01-29 11:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52E8DE7D.5020801@samsung.com>
Hi Marek,
On Wed, Jan 29, 2014 at 10:57:01AM +0000, Marek Szyprowski wrote:
> On 2014-01-16 13:44, Andreas Herrmann wrote:
> > Instead of using just one bitmap to keep track of IO virtual addresses
> > (handed out for IOMMU use) introduce a list of iova_ranges (each
> > having its own bitmap). This allows us to extend existing mappings
> > when running out of iova space for a mapping.
> >
> > If there is not enough space in the mapping to service an IO virtual
> > address allocation request, __alloc_iova() tries to extend the mapping
> > -- by allocating another bitmap -- and makes another allocation
> > attempt using the freshly allocated bitmap.
> >
> > This allows arm iommu drivers to start with a decent initial size when
> > an dma_iommu_mapping is created and still to avoid running out of IO
> > virtual addresses for the mapping.
> >
> > Tests were done on Calxeda ECX-2000 with smmu for sata and xgmac.
> > I've used SZ_512K both for initial mapping size and grow_size.
>
> Thanks for implementing this feature! I remember it was discussed from
> early beginning of arm dma iommu support, but I never had enough time
> to actually implement it. I briefly checked the code and it look fine,
> however I really wonder if we need separate grow_size parameter?
> Personally I would simplify it to simply grow the bitmap by initial
> size until it reaches the maximal size.
That sounds sensible, but I also think it would be worth taking into account
the page sizes supported by the IOMMU as well, since aligning to those makes
sense from a TLB utilisation perspective.
> The whole concept of the simplified bitmap (where 1 bit != 1 page) for
> iova allocation is a specific feature of this code and it has nothing
> to the hardware. After thinking a bit more on the existing
> implementation I've already observed that it is sometimes hard to
> understand the parameters for arm_iommu_create_mapping() function,
> especially the 'order' argument is ofter misunderstood. With your
> patch we got two additional parameters. Maybe it will be much better
> to use only 2 arguments: max_mapping_size and allocation_accuracy.
> The initial bitmap size can be then calculated to fit it into single
> memory page (that's quite important to avoid allocations larger that
> a single memory page). 'allocation_accuracy' will serve the same way
> as 'order' parameter now (but expressed in bytes rather than being
> the multiplier for the number of pages). This way the
> arm_iommu_create_mapping() function should be much easier to
> understand, while keeping the implementation details hidden from the
> caller.
Hmm, I wouldn't guess the SI unit of accuracy to be bytes ;)
Will
^ 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