Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* PCIe trouble on imx6q
From: Kamel BOUHARA @ 2014-01-29 15:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAErSpo6MnY74S=jEemQ9xKDg0xik616MeNE67vROap3orQohGA@mail.gmail.com>

2014-01-29 Bjorn Helgaas <bhelgaas@google.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

Ok, actually I didn't get the host bridge set properly for my board,
here is my DT:


/dts-v1/;
#include "imx6q-phytec-pfla02.dtsi"

/ {
    model = "Phytec phyFLEX-i.MX6 Quad Carrier-Board";
    compatible = "phytec,imx6q-pbab01", "phytec,imx6q-pfla02", "fsl,imx6q";
};

&fec {
    status = "okay";
};

&uart4 {
    status = "okay";
};

&usdhc2 {
    status = "okay";
};

&usdhc3 {
    status = "okay";
};

&pcie {
  status = "okay";
};


Can you give me a example of host configuration ?


BR, Kamel.B

^ permalink raw reply

* [BUG] reproducable ubifs reboot assert and corruption
From: Richard Weinberger @ 2014-01-29 15:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140129154622.GB7278@gmail.com>



Am 29.01.2014 16:46, schrieb Andrew Ruder:
> On Wed, Jan 29, 2014 at 08:30:45AM +0100, Richard Weinberger wrote:
>> BTW: Can you please share your .config?
> 
> No problem.  FYI, this is for a board that is still in development so
> not all my changes have been submitted for inclusion yet.  I would be
> happy to share the changes now if necessary but I've attached the --stat
> to show that as far as mtd/ubifs goes, i'm basically running a stock
> v3.12:

Does the issue also happen if you disable preemption?
i.e. CONFIG_PREEMPT_NONE=y

Maybe it is really a race...

Thanks,
//richard

^ permalink raw reply

* [RFC PATCH 2/3] ARM/ARM64: KVM: Add support for PSCI v0.2 emulation
From: Christoffer Dall @ 2014-01-29 15:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAAhSdy2ny3qhWGMFZcOE1vP1j-iqB9r1Q82fOhUo=NMP1h=JrA@mail.gmail.com>

On Wed, Jan 29, 2014 at 10:22:47AM +0530, Anup Patel wrote:
> On Wed, Jan 29, 2014 at 2:34 AM, Christoffer Dall
> <christoffer.dall@linaro.org> wrote:
> > On Tue, Jan 21, 2014 at 06:31:40PM +0530, Anup Patel wrote:

[...]

> >
> > Which tree does this patch apply to?  It looks like you'll get a
> > conflict with:
> > 478a823 arm: KVM: Don't return PSCI_INVAL if waitqueue is inactive
> 
> This patchset applies on v3.13 tag of Torvalds tree.

That would not contain anything in kvm/next or kvm-arm-next.

> 
> I generally base my patches on latest stable/rc tag of Torvalds tree
> so that I can provide KVM patches to folks interested in trying KVM
> on X-Gene with latest Linux stable/rc.

If you want to make it slightly easier for me or Marc to apply your
patches in general I would recommend basing them off kvm/next or
kvm-arm-next, but it's no big deal.

In this case all you need to consider is already in linus/master.

> 
> I will make sure that revised patchset applies on top of
> 478a823 arm: KVM: Don't return PSCI_INVAL if waitqueue is inactive
> 
> >
> >>       }
> >>
> >> diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
> >> index 0881bf1..ee044a3 100644
> >> --- a/arch/arm/kvm/psci.c
> >> +++ b/arch/arm/kvm/psci.c
> >> @@ -55,13 +55,13 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
> >>       }
> >>
> >>       if (!vcpu)
> >> -             return KVM_PSCI_RET_INVAL;
> >> +             return KVM_PSCI_RET_INVALID_PARAMS;
> >>
> >>       target_pc = *vcpu_reg(source_vcpu, 2);
> >>
> >>       wq = kvm_arch_vcpu_wq(vcpu);
> >>       if (!waitqueue_active(wq))
> >> -             return KVM_PSCI_RET_INVAL;
> >> +             return KVM_PSCI_RET_INVALID_PARAMS;
> >>
> >>       kvm_reset_vcpu(vcpu);
> >>
> >> @@ -84,17 +84,49 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
> >>       return KVM_PSCI_RET_SUCCESS;
> >>  }
> >>
> >> -/**
> >> - * kvm_psci_call - handle PSCI call if r0 value is in range
> >> - * @vcpu: Pointer to the VCPU struct
> >> - *
> >> - * Handle PSCI calls from guests through traps from HVC instructions.
> >> - * The calling convention is similar to SMC calls to the secure world where
> >> - * the function number is placed in r0 and this function returns true if the
> >> - * function number specified in r0 is withing the PSCI range, and false
> >> - * otherwise.
> >> - */
> >> -bool kvm_psci_call(struct kvm_vcpu *vcpu)
> >> +static bool kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
> >> +{
> >> +     unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
> >> +     unsigned long val;
> >> +
> >> +     switch (psci_fn) {
> >> +     case KVM_PSCI_0_2_FN_PSCI_VERSION:
> >> +             /*
> >> +              * Bits[31:16] = Major Version = 0
> >> +              * Bits[15:0] = Minor Version = 2
> >> +              */
> >> +             val = 2;
> >> +             break;
> >> +     case KVM_PSCI_0_2_FN_CPU_OFF:
> >> +             kvm_psci_vcpu_off(vcpu);
> >> +             val = KVM_PSCI_RET_SUCCESS;
> >> +             break;
> >> +     case KVM_PSCI_0_2_FN_CPU_ON:
> >> +     case KVM_PSCI_0_2_FN64_CPU_ON:
> >> +             val = kvm_psci_vcpu_on(vcpu);
> >> +             break;
> >> +     case KVM_PSCI_0_2_FN_CPU_SUSPEND:
> >> +     case KVM_PSCI_0_2_FN_AFFINITY_INFO:
> >> +     case KVM_PSCI_0_2_FN_MIGRATE:
> >> +     case KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
> >> +     case KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
> >> +     case KVM_PSCI_0_2_FN_SYSTEM_OFF:
> >> +     case KVM_PSCI_0_2_FN_SYSTEM_RESET:
> >> +     case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
> >> +     case KVM_PSCI_0_2_FN64_AFFINITY_INFO:
> >> +     case KVM_PSCI_0_2_FN64_MIGRATE:
> >> +     case KVM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
> >> +             val = KVM_PSCI_RET_NOT_SUPPORTED;
> >> +             break;
> >> +     default:
> >> +             return false;
> >> +     }
> >> +
> >> +     *vcpu_reg(vcpu, 0) = val;
> >> +     return true;
> >> +}
> >> +
> >> +static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
> >>  {
> >>       unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
> >>       unsigned long val;
> >> @@ -109,9 +141,8 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu)
> >>               break;
> >>       case KVM_PSCI_FN_CPU_SUSPEND:
> >>       case KVM_PSCI_FN_MIGRATE:
> >> -             val = KVM_PSCI_RET_NI;
> >> +             val = KVM_PSCI_RET_NOT_SUPPORTED;
> >>               break;
> >> -
> >>       default:
> >>               return false;
> >>       }
> >> @@ -119,3 +150,21 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu)
> >>       *vcpu_reg(vcpu, 0) = val;
> >>       return true;
> >>  }
> >> +
> >> +/**
> >> + * kvm_psci_call - handle PSCI call if r0 value is in range
> >> + * @vcpu: Pointer to the VCPU struct
> >> + *
> >> + * Handle PSCI calls from guests through traps from HVC instructions.
> >> + * The calling convention is similar to SMC calls to the secure world where
> >> + * the function number is placed in r0 and this function returns true if the
> >> + * function number specified in r0 is withing the PSCI range, and false
> >> + * otherwise.
> >> + */
> >> +bool kvm_psci_call(struct kvm_vcpu *vcpu)
> >> +{
> >> +     if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
> >> +             return kvm_psci_0_2_call(vcpu);
> >> +
> >> +     return kvm_psci_0_1_call(vcpu);
> >> +}
> >
> > Why don't we just try one after the other?  Do they conflict in some
> > way?
> 
> Atleast the functions IDs are totally different in v0.2 and v0.1
> 
> Also, in v0.2 we have separate function IDs for 32bit and 64bit
> VCPU calling same PSCI function.
> 

So we could just do:

{
	ret = kvm_psci_0_2_call(vcpu);
	if (ret)
		return ret;

	ret = kvm_psci_0_1_call(vcpu);
	if (ret)
		return ret;

	return false;
}

and be rid of the vcpu feature, or?  I thought this was Marc's point in
the last KVM/ARM call?

> >
> > I assume PSCI calls are never going to be in the critical path and calls
> > into PSCI are pretty much expected to be slow as a dog anyhow, so if we
> > could avoid the extra churn in user space code and potential user
> > confusion (providing PSCI 0.2 kernel but too old user space tool for
> > example), I think that would be preferred.
> 
> Yes, PSCI calls will not be in critical path except few functions such as
> PSCI CPU_SUSPEND and CPU_ON.
> 
> For example,
> On real HW, people are very much interested in time taken to resume a
> HW CPU from suspended state because this affects responsiveness of
> a system.
> 

In which case time taken to wake up from suspended state in a VM will
for sure not be dominated by an extra call to a psci function id
checking function.

Thanks,
-Christoffer

^ permalink raw reply

* [BUG] reproducable ubifs reboot assert and corruption
From: Andrew Ruder @ 2014-01-29 15:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52E8AE25.8080502@nod.at>

On Wed, Jan 29, 2014 at 08:30:45AM +0100, Richard Weinberger wrote:
> BTW: Can you please share your .config?

No problem.  FYI, this is for a board that is still in development so
not all my changes have been submitted for inclusion yet.  I would be
happy to share the changes now if necessary but I've attached the --stat
to show that as far as mtd/ubifs goes, i'm basically running a stock
v3.12:

% git diff --stat v3.12..HEAD
 Documentation/devicetree/bindings/usb/pxa-usb.txt |    5 +-
 arch/arm/boot/dts/Makefile                        |    2 +
 arch/arm/boot/dts/pxa270-elecsys_z2.dts           |  330 ++++++
 arch/arm/boot/dts/pxa270-elecsys_z4.dts           |  434 +++++++
 arch/arm/boot/dts/pxa27x.dtsi                     |   13 +-
 arch/arm/boot/dts/pxa2xx.dtsi                     |   14 +-
 arch/arm/boot/dts/pxa3xx.dtsi                     |    4 +
 arch/arm/configs/elecsys_z2_defconfig             | 3089 +++++++++++++++
 arch/arm/mach-pxa/Kconfig                         |   18 +
 arch/arm/mach-pxa/Makefile                        |    3 +-
 arch/arm/mach-pxa/generic.c                       |    3 +-
 arch/arm/mach-pxa/include/mach/hardware.h         |    2 +-
 arch/arm/mach-pxa/irq.c                           |    8 +-
 arch/arm/mach-pxa/{pxa-dt.c => pxa27x-dt.c}       |   44 +-
 arch/arm/mach-pxa/pxa27x.c                        |   25 +-
 arch/arm/mach-pxa/{pxa-dt.c => pxa3xx-dt.c}       |   11 +-
 arch/arm/mach-pxa/sleep.S                         |    2 +-
 drivers/irqchip/Kconfig                           |    8 +
 drivers/irqchip/Makefile                          |    1 +
 drivers/irqchip/irq-zeus.c                        |  192 +++
 drivers/mmc/host/pxamci.c                         |   33 +-
 drivers/net/ethernet/8390/ne.c                    |    4 +-
 drivers/net/ethernet/davicom/dm9000.c             |   68 +-
 drivers/tty/serial/pxa.c                          |    6 +-
 24 files changed, 4222 insertions(+), 97 deletions(-)

And the .config I'm using is attached.

Thanks,
Andy



-------------- next part --------------
A non-text attachment was scrubbed...
Name: config.gz
Type: application/x-gunzip
Size: 14745 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140129/c86abdca/attachment.bin>

^ permalink raw reply

* [PATCH v2] ARM: mm: Fix stage-2 device memory attributes
From: Christoffer Dall @ 2014-01-29 15:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52E8DA5D.9030101@arm.com>

On Wed, Jan 29, 2014 at 10:39:25AM +0000, Marc Zyngier wrote:
> On 28/01/14 21:24, Christoffer Dall wrote:
> > The stage-2 memory attributes are distinct from the Hyp memory
> > attributes and the Stage-1 memory attributes.  We were using the stage-1
> > memory attributes for stage-2 mappings causing device mappings to be
> > mapped as normal memory.  Add the S2 equivalent defines for memory
> > attributes and fix the comments explaining the defines while at it.
> > 
> > Add a prot_pte_s2 field to the mem_type struct and fill out the field
> > for device mappings accordingly.
> > 
> > Cc: Marc Zyngier <marc.zyngier@arm.com>
> > Cc: Catalin Marinas <catalin.marinas@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 
Thanks, Catalin, Russell, any comments?

-Christoffer

^ permalink raw reply

* [BUG] reproducable ubifs reboot assert and corruption
From: Andrew Ruder @ 2014-01-29 15:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52E8AB0F.2090905@nod.at>

On Wed, Jan 29, 2014 at 08:17:35AM +0100, Richard Weinberger wrote:
> So you can trigger this by running fsstress on /mnt and then call
> mount -o remount,ro /mnt?

That's all it takes.  I actually run the remount until it succeeds,
obviously with fsstress going in the background there is a pretty narrow
window where it needs to sneak in with a write between the start of the
sync_filesystem and before the remount check for writers (-EBUSY).

> Can you also trigger it on nandsim or mtdram?

Haven't tried, but I can.  I just don't really have that great of
a development environment for doing this on a desktop machine.

> I did a quick test on my testbed using mtdram and was unable to trigger it.
> But I fear my box is too fast.

I think there is definitely a speed component of my 416 MHz PXA 270 that
makes this pretty easy to hit.  What if you did something like (changing
the ubiattach and mount lines obviously)?

I'll see if I can do this in a qemu, but it might take me a while to get
that setup.

- Andy

^ permalink raw reply

* [PATCH v4 1/1] ARM: davinci: aemif: get rid of davinci-nand driver dependency on aemif
From: Ivan Khoronzhuk @ 2014-01-29 15:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140120184418.GI8919@ld-irv-0074>

Hi Sekhar,

Do you want me to correct it?

On 01/20/2014 08:44 PM, Brian Norris wrote:
> Hi Sekhar,
>
> Sorry, I do have one complaint about this patch.
>
> On Fri, Jan 10, 2014 at 03:06:04PM +0530, Sekhar Nori wrote:
>> --- a/arch/arm/mach-davinci/aemif.c
>> +++ b/arch/arm/mach-davinci/aemif.c
>> @@ -130,4 +136,82 @@ int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
>>   
>>   	return 0;
>>   }
>> -EXPORT_SYMBOL(davinci_aemif_setup_timing);
>> +
>> +/**
>> + * davinci_aemif_setup - setup AEMIF interface by davinci_nand_pdata
>> + * @pdev - link to platform device to setup settings for
>> + *
>> + * This function does not use any locking while programming the AEMIF
>> + * because it is expected that there is only one user of a given
>> + * chip-select.
>> + *
>> + * Returns 0 on success, else negative errno.
>> + */
>> +int davinci_aemif_setup(struct platform_device *pdev)
>> +{
>> +	struct davinci_nand_pdata *pdata = dev_get_platdata(&pdev->dev);
>> +	uint32_t val;
>> +	unsigned long clkrate;
>> +	struct resource	*res;
>> +	void __iomem *base;
>> +	struct clk *clk;
>> +	int ret = 0;
>> +
>> +	clk = clk_get(&pdev->dev, "aemif");
>> +	if (IS_ERR(clk)) {
>> +		ret = PTR_ERR(clk);
>> +		dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = clk_prepare_enable(clk);
>> +	if (ret < 0) {
>> +		dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
>> +			ret);
>> +		return ret;
> coccinelle gives a warning for this:
>
>    arch/arm/mach-davinci/aemif.c:171:2-8: ERROR: missing clk_put; clk_get on line 160 and execution via conditional on line 168 [coccinelle]
>
> You need a clk_put() on the error path for clk_prepare_enable. For
> instance, you can add a label below and replace this 'return ret' with
> 'goto err_put'.
>
>> +	}
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>> +	if (!res) {
>> +		dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n");
>> +		ret = -ENOMEM;
>> +		goto err;
>> +	}
>> +
>> +	base = ioremap(res->start, resource_size(res));
>> +	if (!base) {
>> +		dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res);
>> +		ret = -ENOMEM;
>> +		goto err;
>> +	}
>> +
>> +	/*
>> +	 * Setup Async configuration register in case we did not boot
>> +	 * from NAND and so bootloader did not bother to set it up.
>> +	 */
>> +	val = davinci_aemif_readl(base, A1CR_OFFSET + pdev->id * 4);
>> +	/*
>> +	 * Extended Wait is not valid and Select Strobe mode is not
>> +	 * used
>> +	 */
>> +	val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK);
>> +	if (pdata->options & NAND_BUSWIDTH_16)
>> +		val |= 0x1;
>> +
>> +	davinci_aemif_writel(base, A1CR_OFFSET + pdev->id * 4, val);
>> +
>> +	clkrate = clk_get_rate(clk);
>> +
>> +	if (pdata->timing)
>> +		ret = davinci_aemif_setup_timing(pdata->timing, base, pdev->id,
>> +						 clkrate);
>> +
>> +	if (ret < 0)
>> +		dev_dbg(&pdev->dev, "NAND timing values setup fail\n");
>> +
>> +	iounmap(base);
>> +err:
>> +	clk_disable_unprepare(clk);
> Then the label could be here:
>
> err_put:
>
>> +	clk_put(clk);
>> +	return ret;
>> +}
> Brian

^ permalink raw reply

* [PATCH v5 17/23] drm/i2c: tda998x: set the PLL division factor in range 0..3
From: Joe Perches @ 2014-01-29 15:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <d4ba259762605793aee726b5e33dcad6a8bd4777.1390986083.git.moinejf@free.fr>

On Sat, 2014-01-25 at 18:14 +0100, Jean-Francois Moine wrote:
> The predivider division factor of the register PLL_SERIAL_2 is in the
> range 0..3, the value 0 being used for a division by 1.

trivia:

> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
[]
> @@ -886,6 +886,11 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
>  	}
>  
>  	div = 148500 / mode->clock;
> +	if (div != 0) {
> +		div--;
> +		if (div > 3)
> +			div = 3;
> +	}

perhaps
	clamp(div, 1, 4)
	div--;

^ permalink raw reply

* [PATCH V4 5/5] Documentation: power: reset: Add documentation for generic SYSCON reboot driver
From: Arnd Bergmann @ 2014-01-29 15:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52E2F450.2070100@gmail.com>

On Friday 24 January 2014 15:16:32 Marc C wrote:
> 
> > What's wrong with having a system clock unit binding, that the kernel
> > can decompose as appropriate?
> 
> From what I understand, the arm-soc maintainers want to reduce (and perhaps even
> eliminate) these board-specific constructs, and try to utilize common driver-code that
> resides in the "driver" folder. I can vouch for the syscon/regmap framework as something
> which would enable the effort.

While your statement is true in general, it doesn't seem to counter
what Mark R said above.

	Arnd

^ permalink raw reply

* [Patch v3 2/2] dmaengine: qcom_bam_dma: Add device tree binding
From: Arnd Bergmann @ 2014-01-29 15:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140128121656.GH15937@n2100.arm.linux.org.uk>

On Tuesday 28 January 2014 12:16:56 Russell King - ARM Linux wrote:
> On Tue, Jan 28, 2014 at 01:08:47PM +0100, Arnd Bergmann wrote:
> 
> On balance, I think the virtual channel approach makes client drivers
> more elegant and simpler, and makes the DMA engine API easier to use,
> and gives greater flexibility for future improvements.  So, I wouldn't
> miss the slave_id being removed.

Ok, good. There are some dmaengine drivers that actually behave
in hardware like the virtual-channel extension, i.e. they have
one physical channel per request line (qcom_bam_dma seems to be
one of them in fact), so they don't really have a choice.

The way that both the DT and ACPI bindings are structured,
the request ID is always known by the time the channel is
allocated to allow this model, and that means supporting both
approaches in the same master or slave driver is a mess.

	Arnd

^ permalink raw reply

* [PATCH v3 0/6] efuse driver for Tegra
From: Paul Gortmaker @ 2014-01-29 15:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1390952176-30402-1-git-send-email-pdeschrijver@nvidia.com>

On Tue, Jan 28, 2014 at 6:36 PM, Peter De Schrijver
<pdeschrijver@nvidia.com> wrote:
> This driver allows userspace to read the raw efuse data. Its userspace
> interface is modelled after the sunxi_sid driver which provides similar
> functionality for some Allwinner SoCs. It has been tested on
> Tegra20 (ventana), Tegra30 (beaverboard) and Tegra114 (dalmore).
>
> Changes since v1:
>
> * Add documentation for sysfs interface
> * Cleanup messages
>
> Changes since v2:
>
> * Incorporate early fuse code
> * Remove module support
> * Make driver always build when Tegra platform is selected

Given the above, you should be able to remove #include <linux/module.h>
and MODULE_DEVICE_TABLE, etc.

Paul.
--

> * Add DT binding document
> * Address comments on v2
>
> TODO:
> * test on Tegra124 (venice2)
>
> Peter De Schrijver (6):
>   ARM: tegra: export apb dma readl/writel
>   ARM: tegra: Add chipid, revision and fuse init
>   misc: fuse: Add efuse driver for Tegra
>   ARM: tegra: Add efuse bindings
>   misc: enable fuse drivers
>   ARM: tegra: remove fuse files from mach-tegra
>
>  Documentation/ABI/testing/sysfs-driver-tegra-fuse  |    8 +
>  .../devicetree/bindings/fuse/fuse-tegra.txt        |   32 +++
>  arch/arm/boot/dts/tegra114.dtsi                    |    7 +
>  arch/arm/boot/dts/tegra124.dtsi                    |    7 +
>  arch/arm/boot/dts/tegra20.dtsi                     |    7 +
>  arch/arm/boot/dts/tegra30.dtsi                     |    7 +
>  arch/arm/mach-tegra/Makefile                       |    4 -
>  arch/arm/mach-tegra/apbio.c                        |   51 ++--
>  arch/arm/mach-tegra/cpuidle.c                      |    2 +-
>  arch/arm/mach-tegra/flowctrl.c                     |    2 +-
>  arch/arm/mach-tegra/fuse.c                         |  252 -----------------
>  arch/arm/mach-tegra/fuse.h                         |   79 ------
>  arch/arm/mach-tegra/hotplug.c                      |    2 +-
>  arch/arm/mach-tegra/platsmp.c                      |    2 +-
>  arch/arm/mach-tegra/pm.c                           |    2 +-
>  arch/arm/mach-tegra/pmc.c                          |    2 +-
>  arch/arm/mach-tegra/powergate.c                    |    2 +-
>  arch/arm/mach-tegra/reset-handler.S                |    2 +-
>  arch/arm/mach-tegra/reset.c                        |    2 +-
>  arch/arm/mach-tegra/sleep-tegra30.S                |    2 +-
>  arch/arm/mach-tegra/tegra.c                        |    2 +-
>  arch/arm/mach-tegra/tegra114_speedo.c              |  104 -------
>  arch/arm/mach-tegra/tegra20_speedo.c               |  109 --------
>  arch/arm/mach-tegra/tegra2_emc.c                   |    2 +-
>  arch/arm/mach-tegra/tegra30_speedo.c               |  292 -------------------
>  drivers/misc/Makefile                              |    1 +
>  drivers/misc/fuse/Makefile                         |    1 +
>  drivers/misc/fuse/tegra/Makefile                   |    7 +
>  drivers/misc/fuse/tegra/fuse-tegra.c               |  228 +++++++++++++++
>  drivers/misc/fuse/tegra/fuse-tegra20.c             |  136 +++++++++
>  drivers/misc/fuse/tegra/fuse-tegra30.c             |  178 ++++++++++++
>  drivers/misc/fuse/tegra/fuse.h                     |   82 ++++++
>  drivers/misc/fuse/tegra/tegra114_speedo.c          |  110 ++++++++
>  drivers/misc/fuse/tegra/tegra124_speedo.c          |  164 +++++++++++
>  drivers/misc/fuse/tegra/tegra20_speedo.c           |  110 ++++++++
>  drivers/misc/fuse/tegra/tegra30_speedo.c           |  294 ++++++++++++++++++++
>  include/linux/tegra-soc.h                          |   39 +++
>  37 files changed, 1461 insertions(+), 872 deletions(-)
>  create mode 100644 Documentation/ABI/testing/sysfs-driver-tegra-fuse
>  create mode 100644 Documentation/devicetree/bindings/fuse/fuse-tegra.txt
>  delete mode 100644 arch/arm/mach-tegra/fuse.c
>  delete mode 100644 arch/arm/mach-tegra/fuse.h
>  delete mode 100644 arch/arm/mach-tegra/tegra114_speedo.c
>  delete mode 100644 arch/arm/mach-tegra/tegra20_speedo.c
>  delete mode 100644 arch/arm/mach-tegra/tegra30_speedo.c
>  create mode 100644 drivers/misc/fuse/Makefile
>  create mode 100644 drivers/misc/fuse/tegra/Makefile
>  create mode 100644 drivers/misc/fuse/tegra/fuse-tegra.c
>  create mode 100644 drivers/misc/fuse/tegra/fuse-tegra20.c
>  create mode 100644 drivers/misc/fuse/tegra/fuse-tegra30.c
>  create mode 100644 drivers/misc/fuse/tegra/fuse.h
>  create mode 100644 drivers/misc/fuse/tegra/tegra114_speedo.c
>  create mode 100644 drivers/misc/fuse/tegra/tegra124_speedo.c
>  create mode 100644 drivers/misc/fuse/tegra/tegra20_speedo.c
>  create mode 100644 drivers/misc/fuse/tegra/tegra30_speedo.c
>
> --
> 1.7.7.rc0.72.g4b5ea.dirty
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* imx-drm: screen flickering
From: Marek Vasut @ 2014-01-29 14:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140129111557.GI16215@pengutronix.de>

On Wednesday, January 29, 2014 at 12:15:57 PM, Sascha Hauer wrote:
> 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=sha
> > ring
> > 
> > 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.

Isn't it the clock polarity being inverted thing again [1]?

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2013-
December/215536.html

The easiest way to check this would be to try sig_cfg.clk_pol = 0 or = 1 and see 
if it changes anything.

Best regards,
Marek Vasut

^ permalink raw reply

* [PATCH 1/2] usb: dwc3: core: continue probing if usb phy library returns -ENODEV/-ENXIO
From: Heikki Krogerus @ 2014-01-29 14:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140128163036.GD28546@saruman.home>

Hi,

On Tue, Jan 28, 2014 at 10:30:36AM -0600, Felipe Balbi wrote:
> On Tue, Jan 28, 2014 at 05:32:30PM +0200, Heikki Krogerus wrote:
> > On Mon, Jan 27, 2014 at 10:05:20AM -0600, Felipe Balbi wrote:
> > For the controller drivers the PHYs are just a resource like any
> > other. The controller drivers can't have any responsibility of
> > them. They should not care if PHY drivers are available for them or
> > not, or even if the PHY framework is available or not.
> 
> huh? If memory isn't available you don't continue probing, right ? If
> your IORESOURCE_MEM is missing, you also don't continue probing, if your
> IRQ line is missing, you bail too. Those are also nothing but resources
> to the driver, what you're asking here is to treat PHY as a _different_
> resource; which might be fine, but we need to make sure we don't
> continue probing when a PHY is missing in a platform that certainly
> needs a PHY.

Yes, true. In my head I was comparing the PHY only to resources like
gpios, clocks, dma channels, etc. that are often optional to the
drivers.

> > > > > But I really want to see the argument against using no-op. As far as I
> > > > > could see, everybody needs a PHY driver one way or another, some
> > > > > platforms just haven't sent any PHY driver upstream and have their own
> > > > > hacked up solution to avoid using the PHY layer.
> > > > 
> > > > Not true in our case. Platforms using Intel's SoCs and chip sets may
> > > > or may not have controllable USB PHY. Quite often they don't. The
> > > > Baytrails have usually ULPI PHY for USB2, but that does not mean they
> > > > provide any vendor specific functions or any need for a driver in any
> > > > case.
> > > 
> > > that's different from what I heard.
> > 
> > I don't know where you got that impression, but it's not true. The
> > Baytrail SoCs for example don't have internal USB PHYs, which means
> > the manufacturers using it can select what they want. So we have
> > boards where PHY driver(s) is needed and boards where it isn't.
> 
> alright, that explains it ;-) So you have external USB2 and USB3 PHYs ?
> You have an external PIPE3 interface ? That's quite an achievement,
> kudos to your HW designers. Getting timing closure on PIPE3 is a
> difficult task.

No, only the USB2 PHY is external. I'm giving you wrong information,
I'm sorry about that. Need to concentrate on what I'm writing.

<snip>

> > This is really good to get. We have some projects where we are dealing
> > with more embedded environments, like IVI, where the kernel should be
> > stripped of everything useless. Since the PHYs are autonomous, we
> > should be able to disable the PHY libraries/frameworks.
> 
> hmmm, in that case it's a lot easier to treat. We can use
> ERR_PTR(-ENXIO) as an indication that the framework is disabled, or
> something like that.
> 
> The difficult is really reliably supporting e.g. OMAP5 (which won't work
> without a PHY) and your BayTrail with autonomous PHYs. What can we use
> as an indication ?

OMAP has it's own glue driver, so shouldn't it depend on the PHY
layer?

> I mean, I need to know that a particular platform depends on a PHY
> driver before I decide to return -EPROBE_DEFER or just assume the PHY
> isn't needed ;-)

I don't think dwc3 (core) should care about that. The PHY layer needs
to tell us that. If the PHY driver that the platform depends is not
available yet, the PHY layer returns -EPROBE_DEFER and dwc3 ends up
returning -EPROBE_DEFER.

<snip>

> > I think our goals are the same. I just want to also minimize the need
> > for any platform specific extra work from the upper layers regarding
> > the PHYs.
> 
> I'll agree to that, but let's not apply patches until we're 100% sure
> there will be no regressions. Looking at $subject, I don't think it
> satisfies that condition ;-)

Agreed. Let's think this through carefully.


Cheers,

-- 
heikki

^ permalink raw reply

* [PATCH 11/11] arm: dma-mapping: Add support to extend DMA IOMMU mappings
From: Andreas Herrmann @ 2014-01-29 14:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140129110537.GG26622@mudshark.cambridge.arm.com>

Hi Will, Marek,

On Wed, Jan 29, 2014 at 06:05:37AM -0500, Will Deacon wrote:
> 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.

Meanwhile I also think that the grow_size parameter is overkill. Only
the initial mapping size and the maximum size really matter. Then we
could try to extend the mapping by initial mapping size and if this
fails (we might not have enough pages to serve such an allocation) we
could/should even fall back to allocate a single page (which should
give us at least a 16MB range).

> > 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 ;)
 
Have to think about the alignment argument and the last paragraph for
a while.

All I can say now is that starting with a bitmap size that fits into a
single memory page doesn't sound right to me. The initial allocation
is "easy" (not GFP_ATOMIC) and thus I think we should start with a
larger bitmap. Say you have a device for which at runtime 512MB
mapping range are required and you use a 4k page for the bitmaps (each
tracking 16MB IOVA range) you'll have 32 bitmaps to maintain. Whereas
when you start with 128MB initial bitmap size and (successfully)
enhance the mapping by 128MB you just have to maintain 4 bitmaps.

But of course coming up with the right choice for the initial bitmap
size that fits all master devices is a hard thing to do ...
 


Andreas

^ permalink raw reply

* [RFC] arm: vdso: Convert sigpage to vdso implementation
From: Steve Capper @ 2014-01-29 14:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52E81BB7.7070201@mentor.com>

On Tue, Jan 28, 2014 at 03:05:59PM -0600, Nathan Lynch wrote:
> Hi Steve,
> 
> On 01/28/2014 10:25 AM, Steve Capper wrote:
> > ARM has a special sigpage that is used for signal return trampolines.
> > Its implementation is very similar to a VDSO conceptually in that it
> > occupies a special mapping in user address space.
> > 
> > One could actually host the trampoline code in a VDSO instead with the
> > added advantage that one could also host specialised routines there.
> > One such routine could be gettimeofday where on ARM we have architected
> > (and some vendor supplied) timers that can be queried entirely in
> > userspace, obviating the need for an expensive syscall.
> > 
> > This patch converts the sigpage implementation to a VDSO. It is mostly
> > a direct port from Will Deacon's arm64 implementation with the ARM
> > signal trampoline plumbed in.
> > 
> > Signed-off-by: Steve Capper <steve.capper@linaro.org>
> > ---
> > As can be inferred from this RFC, I am interested ultimately in
> > implementing a syscall-less gettimeofday for ARM. Whilst researching
> > possible vectors page or VDSO implementations, I came across the
> > sigpage mechanism which is very similar to a VDSO.
> > 
> > The very simple function, __kernel_vdso_doubler, resolved in a test
> > program automatically on my Arndale board (running Fedora 20) without
> > any additional prodding.
> > 
> > IPC stress tests from LTP were executed to test the signal trampoline.
> > 
> > I would appreciate any comments on this approach of converting the
> > sigpage to a VDSO. If this looks sane to people, I will work on the
> > gettimeofday logic in a later patch.
> 
> As it happens, I've been working on a vDSO implementation of
> gettimeofday/clock_gettime which does not mess with the signal page.
> I'll reply with the patch separately in a moment.

Cheers Nathan,
-- 
Steve
> 
> 

^ permalink raw reply

* [RFC PATCH v2 14/14] ARM: sunxi/dt: enable HW ECC on cubietruck board
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 arch/arm/boot/dts/sun7i-a20-cubietruck.dts |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 031de97..5828923 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -29,7 +29,7 @@
 				#size-cells = <1>;
 				reg = <0>;
 				allwinner,rb = <0>;
-				nand-ecc-mode = "soft_bch";
+				nand-ecc-mode = "hw";
 
 				/* nand timings */
 				tCLS-min = <6>;
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v2 13/14] mtd: nand: add sunxi HW ECC support
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Add HW ECC support for the sunxi NAND Flash Controller.

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 drivers/mtd/nand/sunxi_nand.c |  279 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 266 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index d3da810..7e1cefc 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -163,6 +163,11 @@ struct sunxi_nand_chip_sel {
 #define DEFAULT_NAME_FORMAT	"nand@%d"
 #define MAX_NAME_SIZE		(sizeof("nand@") + 2)
 
+struct sunxi_nand_hw_ecc {
+	int mode;
+	struct nand_ecclayout layout;
+};
+
 struct sunxi_nand_chip {
 	struct list_head node;
 	struct nand_chip nand;
@@ -402,6 +407,126 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
 	sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
 }
 
+static int sunxi_nfc_hwecc_read_page(struct mtd_info *mtd,
+				     struct nand_chip *chip, uint8_t *buf,
+				     int oob_required, int page)
+{
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct nand_ecclayout *layout = ecc->layout;
+	struct sunxi_nand_hw_ecc *data = ecc->priv;
+	unsigned int max_bitflips = 0;
+	int offset;
+	u32 tmp;
+	int i;
+
+	tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+	tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE |
+		 NFC_ECC_BLOCK_SIZE);
+	tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT);
+	writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+	for (i = 0; i < mtd->writesize / ecc->size; i++) {
+		if (i)
+			chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1);
+		chip->read_buf(mtd, NULL, chip->ecc.size);
+		offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
+		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
+		while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+			;
+		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
+		writel(tmp, nfc->regs + NFC_REG_CMD);
+		sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+		memcpy_fromio(buf + (i * ecc->size), nfc->regs + NFC_RAM0_BASE,
+			      chip->ecc.size);
+
+		if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
+			mtd->ecc_stats.failed++;
+		} else {
+			tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff;
+			mtd->ecc_stats.corrected += tmp;
+			max_bitflips = max_t(unsigned int, max_bitflips, tmp);
+		}
+	}
+
+	if (oob_required) {
+		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+	}
+
+	tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+	tmp &= ~NFC_ECC_EN;
+
+	writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+	return max_bitflips;
+}
+
+static int sunxi_nfc_hwecc_write_page(struct mtd_info *mtd,
+				      struct nand_chip *chip,
+				      const uint8_t *buf,
+				      int oob_required)
+{
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct nand_ecclayout *layout = ecc->layout;
+	struct sunxi_nand_hw_ecc *data = ecc->priv;
+	int offset;
+	u32 tmp;
+	int i;
+	int j;
+
+	tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+	tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE |
+		 NFC_ECC_BLOCK_SIZE);
+	tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT);
+
+	writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+	for (i = 0; i < mtd->writesize / ecc->size; i++) {
+		if (i)
+			chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
+
+		chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
+		offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
+		chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
+		while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+			;
+
+		/* Fill OOB data in */
+		for (j = 0; j < 4; j++) {
+			if (oob_required) {
+				offset = layout->eccpos[i * ecc->size] - 4;
+				writeb(chip->oob_poi[offset + j],
+				       nfc->regs + NFC_REG_USER_DATA_BASE + j);
+			} else {
+				writeb(0xff,
+				       nfc->regs + NFC_REG_USER_DATA_BASE + j);
+			}
+		}
+
+		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+		      NFC_ACCESS_DIR | (1 << 30);
+		writel(tmp, nfc->regs + NFC_REG_CMD);
+		sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+	}
+
+	if (oob_required && chip->ecc.layout->oobfree[0].length > 2) {
+		chip->cmdfunc(mtd, NAND_CMD_RNDIN, mtd->writesize, -1);
+		chip->write_buf(mtd, chip->oob_poi,
+				chip->ecc.layout->oobfree[0].length - 2);
+	}
+
+	tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+	tmp &= ~(NFC_ECC_EN | NFC_ECC_PIPELINE);
+
+	writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+	return 0;
+}
+
 static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
 					struct device_node *np)
 {
@@ -502,6 +627,144 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
 	return 0;
 }
 
+static int sunxi_nand_chip_hwecc_init(struct device *dev,
+				      struct sunxi_nand_chip *chip,
+				      struct mtd_info *mtd,
+				      struct device_node *np)
+{
+	struct nand_chip *nand = &chip->nand;
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	struct sunxi_nand_hw_ecc *data;
+	struct nand_ecclayout *layout;
+	int nsectors;
+	int i;
+	int j;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	ecc->read_page = sunxi_nfc_hwecc_read_page;
+	ecc->write_page = sunxi_nfc_hwecc_write_page;
+
+	if (nand->ecc_strength_ds <= 16) {
+		nand->ecc_strength_ds = 16;
+		data->mode = 0;
+	} else if (nand->ecc_strength_ds <= 24) {
+		nand->ecc_strength_ds = 24;
+		data->mode = 1;
+	} else if (nand->ecc_strength_ds <= 28) {
+		nand->ecc_strength_ds = 28;
+		data->mode = 2;
+	} else if (nand->ecc_strength_ds <= 32) {
+		nand->ecc_strength_ds = 32;
+		data->mode = 3;
+	} else if (nand->ecc_strength_ds <= 40) {
+		nand->ecc_strength_ds = 40;
+		data->mode = 4;
+	} else if (nand->ecc_strength_ds <= 48) {
+		nand->ecc_strength_ds = 48;
+		data->mode = 5;
+	} else if (nand->ecc_strength_ds <= 56) {
+		nand->ecc_strength_ds = 56;
+		data->mode = 6;
+	} else if (nand->ecc_strength_ds <= 60) {
+		nand->ecc_strength_ds = 60;
+		data->mode = 7;
+	} else if (nand->ecc_strength_ds <= 64) {
+		nand->ecc_strength_ds = 64;
+		data->mode = 8;
+	} else {
+		dev_err(dev, "unsupported strength\n");
+		return -ENOTSUPP;
+	}
+
+	/* HW ECC always request ECC bytes for 1024 bytes blocks */
+	ecc->bytes = ((nand->ecc_strength_ds * fls(8 * 1024)) + 7) / 8;
+
+	/* HW ECC always work with even numbers of ECC bytes */
+	if (ecc->bytes % 2)
+		ecc->bytes++;
+	ecc->strength = nand->ecc_strength_ds;
+	ecc->size = nand->ecc_step_ds;
+
+	layout = &data->layout;
+	nsectors = mtd->writesize / ecc->size;
+
+	if (mtd->oobsize < ((ecc->bytes + 4) * nsectors))
+		return -EINVAL;
+
+	layout->eccbytes = (ecc->bytes * nsectors);
+
+	/*
+	 * The first 2 bytes are used for BB markers.
+	 * We merge the 4 user available bytes from HW ECC with this
+	 * first section, hence why the + 2 operation (- 2 + 4).
+	 */
+	layout->oobfree[0].length = mtd->oobsize + 2 -
+				    ((ecc->bytes + 4) * nsectors);
+	layout->oobfree[0].offset = 2;
+	for (i = 0; i < nsectors; i++) {
+		/*
+		 * The first 4 ECC block bytes are already counted in the first
+		 * obbfree entry.
+		 */
+		if (i) {
+			layout->oobfree[i].offset =
+				layout->oobfree[i - 1].offset +
+				layout->oobfree[i - 1].length +
+				ecc->bytes;
+			layout->oobfree[i].length = 4;
+		}
+
+		for (j = 0; j < ecc->bytes; j++)
+			layout->eccpos[(ecc->bytes * i) + j] =
+					layout->oobfree[i].offset +
+					layout->oobfree[i].length + j;
+	}
+
+	ecc->layout = layout;
+	ecc->priv = data;
+
+	return 0;
+}
+
+static int sunxi_nand_chip_ecc_init(struct device *dev,
+				    struct sunxi_nand_chip *chip,
+				    struct mtd_info *mtd,
+				    struct device_node *np)
+{
+	struct nand_chip *nand = &chip->nand;
+	u32 strength;
+	u32 blk_size;
+	int ret;
+
+	nand->ecc.mode = of_get_nand_ecc_mode(np);
+
+	if (!of_get_nand_ecc_level(np, &strength, &blk_size)) {
+		nand->ecc_step_ds = blk_size;
+		nand->ecc_strength_ds = strength;
+	}
+
+	switch (nand->ecc.mode) {
+	case NAND_ECC_SOFT_BCH:
+		nand->ecc.size = nand->ecc_step_ds;
+		nand->ecc.bytes = ((nand->ecc_strength_ds *
+				    fls(8 * nand->ecc_step_ds)) + 7) / 8;
+		break;
+	case NAND_ECC_HW:
+		ret = sunxi_nand_chip_hwecc_init(dev, chip, mtd, np);
+		if (ret)
+			return ret;
+		break;
+	case NAND_ECC_NONE:
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 				struct device_node *np)
 {
@@ -509,8 +772,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 	struct mtd_part_parser_data ppdata;
 	struct mtd_info *mtd;
 	struct nand_chip *nand;
-	u32 strength;
-	u32 blk_size;
 	int nsels;
 	int ret;
 	int i;
@@ -576,7 +837,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 	nand->write_buf = sunxi_nfc_write_buf;
 	nand->read_byte = sunxi_nfc_read_byte;
 
-	nand->ecc.mode = of_get_nand_ecc_mode(np);
 	if (of_get_nand_on_flash_bbt(np))
 		nand->bbt_options |= NAND_BBT_USE_FLASH;
 
@@ -588,16 +848,9 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 	if (ret)
 		return ret;
 
-	if (nand->ecc.mode == NAND_ECC_SOFT_BCH) {
-		if (!of_get_nand_ecc_level(np, &strength, &blk_size)) {
-			nand->ecc_step_ds = blk_size;
-			nand->ecc_strength_ds = strength;
-		}
-
-		nand->ecc.size = nand->ecc_step_ds;
-		nand->ecc.bytes = (((nand->ecc_strength_ds *
-				     fls(8 * nand->ecc_step_ds)) + 7) / 8);
-	}
+	ret = sunxi_nand_chip_ecc_init(dev, chip, mtd, np);
+	if (ret)
+		return ret;
 
 	ret = nand_scan_tail(mtd);
 	if (ret)
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v2 12/14] ARM: sunxi/dt: enable NAND on cubietruck board
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Enable the NFC and describe the NAND flash connected to this controller.

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 arch/arm/boot/dts/sun7i-a20-cubietruck.dts |   31 ++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 8a1009d..031de97 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -19,6 +19,37 @@
 	compatible = "cubietech,cubietruck", "allwinner,sun7i-a20";
 
 	soc at 01c00000 {
+		nfc: nand at 01c03000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+			status = "okay";
+
+			nand at 0 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0>;
+				allwinner,rb = <0>;
+				nand-ecc-mode = "soft_bch";
+
+				/* nand timings */
+				tCLS-min = <6>;
+				tCLH-min = <3>;
+				tCS-min = <20>;
+				tCH-min = <5>;
+				tWP-min = <8>;
+				tWH-min = <6>;
+				tALS-min = <6>;
+				tDS-min = <6>;
+				tDH-min = <2>;
+				tRR-min = <20>;
+				tALH-min = <3>;
+				tRP-min = <8>;
+				tREH-min = <6>;
+				tRC-min = <16>;
+				tWC-min = <16>;
+			};
+		};
+
 		pinctrl at 01c20800 {
 			led_pins_cubietruck: led_pins at 0 {
 				allwinner,pins = "PH7", "PH11", "PH20", "PH21";
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v2 11/14] ARM: dt/sunxi: add NFC pinctrl pin definitions
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Define the NAND pinctrl configs.

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 arch/arm/boot/dts/sun7i-a20.dtsi |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 3b47253..0f6e002 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -389,6 +389,30 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			nand_pins_a: nand_base0 at 0 {
+				allwinner,pins = "PC0", "PC1", "PC2",
+						"PC5", "PC8", "PC9", "PC10",
+						"PC11", "PC12", "PC13", "PC14",
+						"PC15", "PC16";
+				allwinner,function = "nand0";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			nand_cs0_pins_a: nand_cs at 0 {
+				allwinner,pins = "PC4";
+				allwinner,function = "nand0";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			nand_rb0_pins_a: nand_rb at 0 {
+				allwinner,pins = "PC6";
+				allwinner,function = "nand0";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
 		};
 
 		timer at 01c20c00 {
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v2 10/14] ARM: dt/sunxi: add NFC node to Allwinner A20 SoC
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Add NAND Flash controller node definition to the A20 SoC.

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 arch/arm/boot/dts/sun7i-a20.dtsi |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 8e4cdcc..3b47253 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -299,6 +299,17 @@
 		#size-cells = <1>;
 		ranges;
 
+		nfc: nand at 01c03000 {
+			compatible = "allwinner,sun4i-nand";
+			reg = <0x01c03000 0x1000>;
+			interrupts = <0 37 1>;
+			clocks = <&ahb_gates 13>, <&nand_clk>;
+			clock-names = "ahb_clk", "sclk";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
 		emac: ethernet at 01c0b000 {
 			compatible = "allwinner,sun4i-emac";
 			reg = <0x01c0b000 0x1000>;
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v2 09/14] mtd: nand: add sunxi NFC dt bindings doc
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Add the sunxi NAND Flash Controller dt bindings documentation.

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 .../devicetree/bindings/mtd/sunxi-nand.txt         |   46 ++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/sunxi-nand.txt

diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt
new file mode 100644
index 0000000..b0e55a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt
@@ -0,0 +1,46 @@
+Allwinner NAND Flash Controller (NFC)
+
+Required properties:
+- compatible : "allwinner,sun4i-nand".
+- reg : shall contain registers location and length for data and reg.
+- interrupts : shall define the nand controller interrupt.
+- #address-cells: shall be set to 1. Encode the nand CS.
+- #size-cells : shall be set to 0.
+- clocks : shall reference nand controller clocks.
+- clock-names : nand controller internal clock names. Shall contain :
+    * "ahb_clk" : AHB gating clock
+    * "sclk" : nand controller clock
+
+Optional children nodes:
+Children nodes represent the available nand chips.
+
+Optional properties:
+- onfi,nand-timing-mode : mandatory if the chip does not support the ONFI
+  standard.
+- allwinner,rb : shall contain the native Ready/Busy ids.
+ or
+- rb-gpios : shall contain the gpios used as R/B pins.
+
+see Documentation/devicetree/mtd/nand.txt for generic bindings.
+
+
+Examples:
+nfc: nand at 01c03000 {
+	compatible = "allwinner,sun4i-nand";
+	reg = <0x01c03000 0x1000>;
+	interrupts = <0 37 1>;
+	clocks = <&ahb_gates 13>, <&nand_clk>;
+	clock-names = "ahb_clk", "sclk";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+	status = "okay";
+
+	nand at 0 {
+		reg = <0>;
+		allwinner,rb = <0>;
+		nand-ecc-mode = "soft_bch";
+		onfi,nand-timing-mode = <4>;
+	};
+};
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v2 08/14] mtd: nand: add sunxi NAND flash controller support
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Add support for the sunxi NAND Flash Controller (NFC).

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 drivers/mtd/nand/Kconfig      |    6 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/sunxi_nand.c |  744 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 751 insertions(+)
 create mode 100644 drivers/mtd/nand/sunxi_nand.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 93ae6a6..784dd42 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -510,4 +510,10 @@ config MTD_NAND_XWAY
 	  Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
 	  to the External Bus Unit (EBU).
 
+config MTD_NAND_SUNXI
+	tristate "Support for NAND on Allwinner SoCs"
+	depends on ARCH_SUNXI
+	help
+	  Enables support for NAND Flash chips on Allwinner SoCs.
+
 endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index bbea7a6..e3b4a34 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -49,5 +49,6 @@ obj-$(CONFIG_MTD_NAND_JZ4740)		+= jz4740_nand.o
 obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/
 obj-$(CONFIG_MTD_NAND_XWAY)		+= xway_nand.o
 obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
+obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
new file mode 100644
index 0000000..d3da810
--- /dev/null
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com>
+ *
+ * Derived from:
+ *	https://github.com/yuq/sunxi-nfc-mtd
+ *	Copyright (C) 2013 Qiang Yu <yuq825@gmail.com>
+ *
+ *	https://github.com/hno/Allwinner-Info
+ *	Copyright (C) 2013 Henrik Nordstr?m <Henrik Nordstr?m>
+ *
+ *	Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com>
+ *	Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_mtd.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#define NFC_REG_CTL		0x0000
+#define NFC_REG_ST		0x0004
+#define NFC_REG_INT		0x0008
+#define NFC_REG_TIMING_CTL	0x000C
+#define NFC_REG_TIMING_CFG	0x0010
+#define NFC_REG_ADDR_LOW	0x0014
+#define NFC_REG_ADDR_HIGH	0x0018
+#define NFC_REG_SECTOR_NUM	0x001C
+#define NFC_REG_CNT		0x0020
+#define NFC_REG_CMD		0x0024
+#define NFC_REG_RCMD_SET	0x0028
+#define NFC_REG_WCMD_SET	0x002C
+#define NFC_REG_IO_DATA		0x0030
+#define NFC_REG_ECC_CTL		0x0034
+#define NFC_REG_ECC_ST		0x0038
+#define NFC_REG_DEBUG		0x003C
+#define NFC_REG_ECC_CNT0	0x0040
+#define NFC_REG_ECC_CNT1	0x0044
+#define NFC_REG_ECC_CNT2	0x0048
+#define NFC_REG_ECC_CNT3	0x004c
+#define NFC_REG_USER_DATA_BASE	0x0050
+#define NFC_REG_SPARE_AREA	0x00A0
+#define NFC_RAM0_BASE		0x0400
+#define NFC_RAM1_BASE		0x0800
+
+/*define bit use in NFC_CTL*/
+#define NFC_EN				(1 << 0)
+#define NFC_RESET			(1 << 1)
+#define NFC_BUS_WIDYH			(1 << 2)
+#define NFC_RB_SEL			(1 << 3)
+#define NFC_CE_SEL			(7 << 24)
+#define NFC_CE_CTL			(1 << 6)
+#define NFC_CE_CTL1			(1 << 7)
+#define NFC_PAGE_SIZE			(0xf << 8)
+#define NFC_SAM				(1 << 12)
+#define NFC_RAM_METHOD			(1 << 14)
+#define NFC_DEBUG_CTL			(1 << 31)
+
+/*define bit use in NFC_ST*/
+#define NFC_RB_B2R			(1 << 0)
+#define NFC_CMD_INT_FLAG		(1 << 1)
+#define NFC_DMA_INT_FLAG		(1 << 2)
+#define NFC_CMD_FIFO_STATUS		(1 << 3)
+#define NFC_STA				(1 << 4)
+#define NFC_NATCH_INT_FLAG		(1 << 5)
+#define NFC_RB_STATE0			(1 << 8)
+#define NFC_RB_STATE1			(1 << 9)
+#define NFC_RB_STATE2			(1 << 10)
+#define NFC_RB_STATE3			(1 << 11)
+
+/*define bit use in NFC_INT*/
+#define NFC_B2R_INT_ENABLE		(1 << 0)
+#define NFC_CMD_INT_ENABLE		(1 << 1)
+#define NFC_DMA_INT_ENABLE		(1 << 2)
+#define NFC_INT_MASK			(NFC_B2R_INT_ENABLE | \
+					 NFC_CMD_INT_ENABLE | \
+					 NFC_DMA_INT_ENABLE)
+
+
+/*define bit use in NFC_CMD*/
+#define NFC_CMD_LOW_BYTE		(0xff << 0)
+#define NFC_CMD_HIGH_BYTE		(0xff << 8)
+#define NFC_ADR_NUM			(0x7 << 16)
+#define NFC_SEND_ADR			(1 << 19)
+#define NFC_ACCESS_DIR			(1 << 20)
+#define NFC_DATA_TRANS			(1 << 21)
+#define NFC_SEND_CMD1			(1 << 22)
+#define NFC_WAIT_FLAG			(1 << 23)
+#define NFC_SEND_CMD2			(1 << 24)
+#define NFC_SEQ				(1 << 25)
+#define NFC_DATA_SWAP_METHOD		(1 << 26)
+#define NFC_ROW_AUTO_INC		(1 << 27)
+#define NFC_SEND_CMD3			(1 << 28)
+#define NFC_SEND_CMD4			(1 << 29)
+#define NFC_CMD_TYPE			(3 << 30)
+
+/* define bit use in NFC_RCMD_SET*/
+#define NFC_READ_CMD			(0xff << 0)
+#define NFC_RANDOM_READ_CMD0		(0xff << 8)
+#define NFC_RANDOM_READ_CMD1		(0xff << 16)
+
+/*define bit use in NFC_WCMD_SET*/
+#define NFC_PROGRAM_CMD			(0xff << 0)
+#define NFC_RANDOM_WRITE_CMD		(0xff << 8)
+#define NFC_READ_CMD0			(0xff << 16)
+#define NFC_READ_CMD1			(0xff << 24)
+
+/*define bit use in NFC_ECC_CTL*/
+#define NFC_ECC_EN			(1 << 0)
+#define NFC_ECC_PIPELINE		(1 << 3)
+#define NFC_ECC_EXCEPTION		(1 << 4)
+#define NFC_ECC_BLOCK_SIZE		(1 << 5)
+#define NFC_RANDOM_EN			(1 << 9)
+#define NFC_RANDOM_DIRECTION		(1 << 10)
+#define NFC_ECC_MODE_SHIFT		12
+#define NFC_ECC_MODE			(0xf << NFC_ECC_MODE_SHIFT)
+#define NFC_RANDOM_SEED			(0x7fff << 16)
+
+
+
+enum sunxi_nand_rb_type {
+	RB_NONE,
+	RB_NATIVE,
+	RB_GPIO,
+};
+
+struct sunxi_nand_rb {
+	enum sunxi_nand_rb_type type;
+	union {
+		int gpio;
+		int nativeid;
+	} info;
+};
+
+struct sunxi_nand_chip_sel {
+	u8 cs;
+	struct sunxi_nand_rb rb;
+};
+
+#define DEFAULT_NAME_FORMAT	"nand@%d"
+#define MAX_NAME_SIZE		(sizeof("nand@") + 2)
+
+struct sunxi_nand_chip {
+	struct list_head node;
+	struct nand_chip nand;
+	struct mtd_info mtd;
+	char default_name[MAX_NAME_SIZE];
+	unsigned long clk_rate;
+	int selected;
+	int nsels;
+	struct sunxi_nand_chip_sel sels[0];
+};
+
+static inline struct sunxi_nand_chip *to_sunxi_nand(struct mtd_info *mtd)
+{
+	return container_of(mtd, struct sunxi_nand_chip, mtd);
+}
+
+struct sunxi_nfc {
+	struct nand_hw_control controller;
+	void __iomem *regs;
+	int irq;
+	struct clk *ahb_clk;
+	struct clk *sclk;
+	unsigned long assigned_cs;
+	unsigned long clk_rate;
+	struct list_head chips;
+	struct completion complete;
+};
+
+static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
+{
+	return container_of(ctrl, struct sunxi_nfc, controller);
+}
+
+static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
+{
+	struct sunxi_nfc *nfc = dev_id;
+	u32 st = readl(nfc->regs + NFC_REG_ST);
+	u32 ien = readl(nfc->regs + NFC_REG_INT);
+
+	if (!(ien & st))
+		return IRQ_NONE;
+
+	if ((ien & st) == ien)
+		complete(&nfc->complete);
+
+	writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
+	writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT);
+
+	return IRQ_HANDLED;
+}
+
+static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags,
+			      unsigned int timeout_ms)
+{
+	init_completion(&nfc->complete);
+
+	writel(flags, nfc->regs + NFC_REG_INT);
+	if (!timeout_ms)
+		wait_for_completion(&nfc->complete);
+	else if (!wait_for_completion_timeout(&nfc->complete,
+					      msecs_to_jiffies(timeout_ms)))
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
+{
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	struct sunxi_nand_rb *rb;
+	unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20);
+	int ret;
+
+	if (sunxi_nand->selected < 0)
+		return 0;
+
+	rb = &sunxi_nand->sels[sunxi_nand->selected].rb;
+
+	switch (rb->type) {
+	case RB_NATIVE:
+		ret = !!(readl(nfc->regs + NFC_REG_ST) &
+			 (NFC_RB_STATE0 << rb->info.nativeid));
+		if (ret)
+			break;
+
+		sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo);
+		ret = !!(readl(nfc->regs + NFC_REG_ST) &
+			 (NFC_RB_STATE0 << rb->info.nativeid));
+		break;
+	case RB_GPIO:
+		ret = gpio_get_value(rb->info.gpio);
+		break;
+	case RB_NONE:
+	default:
+		ret = 0;
+		dev_err(&mtd->dev, "cannot check R/B NAND status!");
+		break;
+	}
+
+	return ret;
+}
+
+static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+	struct nand_chip *nand = &sunxi_nand->nand;
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	struct sunxi_nand_chip_sel *sel;
+	u32 ctl;
+
+	if (chip > 0 && chip >= sunxi_nand->nsels)
+		return;
+
+	if (chip == sunxi_nand->selected)
+		return;
+
+	ctl = readl(nfc->regs + NFC_REG_CTL) &
+	      ~(NFC_CE_SEL | NFC_RB_SEL | NFC_EN);
+
+	if (chip >= 0) {
+		sel = &sunxi_nand->sels[chip];
+
+		ctl |= (sel->cs << 24) | NFC_EN |
+		       (((nand->page_shift - 10) & 0xf) << 8);
+		if (sel->rb.type == RB_NONE) {
+			nand->dev_ready = NULL;
+		} else {
+			nand->dev_ready = sunxi_nfc_dev_ready;
+			if (sel->rb.type == RB_NATIVE)
+				ctl |= (sel->rb.info.nativeid << 3);
+		}
+
+		writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
+
+		if (nfc->clk_rate != sunxi_nand->clk_rate) {
+			clk_set_rate(nfc->sclk, sunxi_nand->clk_rate);
+			nfc->clk_rate = sunxi_nand->clk_rate;
+		}
+	}
+
+	writel(ctl, nfc->regs + NFC_REG_CTL);
+
+	sunxi_nand->selected = chip;
+}
+
+static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	int cnt;
+	int offs = 0;
+	u32 tmp;
+
+	while (len > offs) {
+		cnt = len - offs;
+		if (cnt > 1024)
+			cnt = 1024;
+
+		while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+			;
+		writel(cnt, nfc->regs + NFC_REG_CNT);
+		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
+		writel(tmp, nfc->regs + NFC_REG_CMD);
+		sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+		if (buf)
+			memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
+				      cnt);
+		offs += cnt;
+	}
+}
+
+static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+				int len)
+{
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	int cnt;
+	int offs = 0;
+	u32 tmp;
+
+	while (len > offs) {
+		cnt = len - offs;
+		if (cnt > 1024)
+			cnt = 1024;
+
+		while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+			;
+		writel(cnt, nfc->regs + NFC_REG_CNT);
+		memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
+		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+		      NFC_ACCESS_DIR;
+		writel(tmp, nfc->regs + NFC_REG_CMD);
+		sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+		offs += cnt;
+	}
+}
+
+static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
+{
+	uint8_t ret;
+
+	sunxi_nfc_read_buf(mtd, &ret, 1);
+
+	return ret;
+}
+
+static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
+			       unsigned int ctrl)
+{
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	u32 tmp;
+
+	while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+		;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		tmp = readl(nfc->regs + NFC_REG_CTL);
+		if (ctrl & NAND_NCE)
+			tmp |= NFC_CE_CTL;
+		else
+			tmp &= ~NFC_CE_CTL;
+		writel(tmp, nfc->regs + NFC_REG_CTL);
+	}
+
+	if (dat == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE) {
+		writel(NFC_SEND_CMD1 | dat, nfc->regs + NFC_REG_CMD);
+	} else {
+		writel(dat, nfc->regs + NFC_REG_ADDR_LOW);
+		writel(NFC_SEND_ADR, nfc->regs + NFC_REG_CMD);
+	}
+
+	sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+}
+
+static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
+					struct device_node *np)
+{
+	const struct nand_sdr_timings *timings;
+	u32 min_clk_period = 0;
+	int ret;
+
+	ret = onfi_get_async_timing_mode(&chip->nand);
+	if (ret == ONFI_TIMING_MODE_UNKNOWN) {
+		ret = of_get_nand_onfi_timing_mode(np);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = fls(ret);
+	if (!ret)
+		return -EINVAL;
+
+	timings = onfi_async_timing_mode_to_sdr_timings(ret - 1);
+	if (IS_ERR(timings))
+		return PTR_ERR(timings);
+
+	/* NFC timings defined in Allwinner Datasheets */
+
+	/* T1 <=> tCLS */
+	if (timings->tCLS_min > min_clk_period)
+		min_clk_period = timings->tCLS_min;
+
+	/* T2 <=> tCLH */
+	if (timings->tCLH_min > min_clk_period)
+		min_clk_period = timings->tCLH_min;
+
+	/* T3 <=> tCS */
+	if (timings->tCS_min > min_clk_period)
+		min_clk_period = timings->tCS_min;
+
+	/* T4 <=> tCH */
+	if (timings->tCH_min > min_clk_period)
+		min_clk_period = timings->tCH_min;
+
+	/* T5 <=> tWP */
+	if (timings->tWP_min > min_clk_period)
+		min_clk_period = timings->tWP_min;
+
+	/* T6 <=> tWH */
+	if (timings->tWH_min > min_clk_period)
+		min_clk_period = timings->tWH_min;
+
+	/* T7 <=> tALS */
+	if (timings->tALS_min > min_clk_period)
+		min_clk_period = timings->tALS_min;
+
+	/* T8 <=> tDS */
+	if (timings->tDS_min > min_clk_period)
+		min_clk_period = timings->tDS_min;
+
+	/* T9 <=> tDH */
+	if (timings->tDH_min > min_clk_period)
+		min_clk_period = timings->tDH_min;
+
+	/* T10 <=> tRR */
+	if (timings->tRR_min > (min_clk_period * 3))
+		min_clk_period = (timings->tRR_min + 2) / 3;
+
+	/* T11 <=> tALH */
+	if (timings->tALH_min > min_clk_period)
+		min_clk_period = timings->tALH_min;
+
+	/* T12 <=> tRP */
+	if (timings->tRP_min > min_clk_period)
+		min_clk_period = timings->tRP_min;
+
+	/* T13 <=> tREH */
+	if (timings->tREH_min > min_clk_period)
+		min_clk_period = timings->tREH_min;
+
+	/* T14 <=> tRC */
+	if (timings->tRC_min > (min_clk_period * 2))
+		min_clk_period = (timings->tRC_min + 1) / 2;
+
+	/* T15 <=> tWC */
+	if (timings->tWC_min > (min_clk_period * 2))
+		min_clk_period = (timings->tWC_min + 1) / 2;
+
+
+	/* min_clk_period = (NAND-clk-period * 2) */
+	if (!min_clk_period) {
+		chip->clk_rate = 20000000;
+	} else {
+		min_clk_period /= 1000;
+		if (!min_clk_period)
+			min_clk_period = 1;
+		chip->clk_rate = (2 * 1000000000) / min_clk_period;
+	}
+
+	/* TODO: configure T16-T19 */
+
+	return 0;
+}
+
+static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
+				struct device_node *np)
+{
+	struct sunxi_nand_chip *chip;
+	struct mtd_part_parser_data ppdata;
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	u32 strength;
+	u32 blk_size;
+	int nsels;
+	int ret;
+	int i;
+	u32 tmp;
+
+	if (!of_get_property(np, "reg", &nsels))
+		return -EINVAL;
+
+	nsels /= sizeof(u32);
+	if (!nsels)
+		return -EINVAL;
+
+	chip = devm_kzalloc(dev,
+			    sizeof(*chip) +
+			    (nsels * sizeof(struct sunxi_nand_chip_sel)),
+			    GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->nsels = nsels;
+	chip->selected = -1;
+
+	for (i = 0; i < nsels; i++) {
+		ret = of_property_read_u32_index(np, "reg", i, &tmp);
+		if (ret)
+			return ret;
+
+		if (tmp > 7)
+			return -EINVAL;
+
+		if (test_and_set_bit(tmp, &nfc->assigned_cs))
+			return -EINVAL;
+
+		chip->sels[i].cs = tmp;
+
+		if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
+		    tmp < 2) {
+			chip->sels[i].rb.type = RB_NATIVE;
+			chip->sels[i].rb.info.nativeid = tmp;
+		} else {
+			ret = of_get_named_gpio(np, "rb-gpios", i);
+			if (ret >= 0) {
+				chip->sels[i].rb.type = RB_GPIO;
+				chip->sels[i].rb.info.gpio = tmp;
+				ret = devm_gpio_request(dev, tmp, "nand-rb");
+				if (ret)
+					return ret;
+			} else {
+				chip->sels[i].rb.type = RB_NONE;
+			}
+		}
+	}
+
+	ret = sunxi_nand_chip_init_timings(chip, np);
+	if (ret)
+		return ret;
+
+	nand = &chip->nand;
+	nand->controller = &nfc->controller;
+	nand->select_chip = sunxi_nfc_select_chip;
+	nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
+	nand->read_buf = sunxi_nfc_read_buf;
+	nand->write_buf = sunxi_nfc_write_buf;
+	nand->read_byte = sunxi_nfc_read_byte;
+
+	nand->ecc.mode = of_get_nand_ecc_mode(np);
+	if (of_get_nand_on_flash_bbt(np))
+		nand->bbt_options |= NAND_BBT_USE_FLASH;
+
+	mtd = &chip->mtd;
+	mtd->priv = nand;
+	mtd->owner = THIS_MODULE;
+
+	ret = nand_scan_ident(mtd, nsels, NULL);
+	if (ret)
+		return ret;
+
+	if (nand->ecc.mode == NAND_ECC_SOFT_BCH) {
+		if (!of_get_nand_ecc_level(np, &strength, &blk_size)) {
+			nand->ecc_step_ds = blk_size;
+			nand->ecc_strength_ds = strength;
+		}
+
+		nand->ecc.size = nand->ecc_step_ds;
+		nand->ecc.bytes = (((nand->ecc_strength_ds *
+				     fls(8 * nand->ecc_step_ds)) + 7) / 8);
+	}
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		return ret;
+
+	if (of_property_read_string(np, "nand-name", &mtd->name)) {
+		snprintf(chip->default_name, MAX_NAME_SIZE,
+			 DEFAULT_NAME_FORMAT, chip->sels[i].cs);
+		mtd->name = chip->default_name;
+	}
+
+	ppdata.of_node = np;
+	ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+	if (!ret)
+		return ret;
+
+	list_add_tail(&chip->node, &nfc->chips);
+
+	return 0;
+}
+
+static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *nand_np;
+	int nchips = of_get_child_count(np);
+	int ret;
+
+	if (nchips > 8)
+		return -EINVAL;
+
+	for_each_child_of_node(np, nand_np) {
+		ret = sunxi_nand_chip_init(dev, nfc, nand_np);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int sunxi_nfc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *r;
+	struct sunxi_nfc *nfc;
+	int ret;
+
+	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+	if (!nfc) {
+		dev_err(dev, "failed to allocate NFC struct\n");
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&nfc->controller.lock);
+	init_waitqueue_head(&nfc->controller.wq);
+	INIT_LIST_HEAD(&nfc->chips);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->regs = devm_ioremap_resource(dev, r);
+	if (IS_ERR(nfc->regs)) {
+		dev_err(dev, "failed to remap iomem\n");
+		return PTR_ERR(nfc->regs);
+	}
+
+	nfc->irq = platform_get_irq(pdev, 0);
+	if (nfc->irq < 0) {
+		dev_err(dev, "failed to retrieve irq\n");
+		return nfc->irq;
+	}
+
+	nfc->ahb_clk = devm_clk_get(dev, "ahb_clk");
+	if (IS_ERR(nfc->ahb_clk)) {
+		dev_err(dev, "failed to retrieve ahb_clk\n");
+		return PTR_ERR(nfc->ahb_clk);
+	}
+
+	ret = clk_prepare_enable(nfc->ahb_clk);
+	if (ret)
+		return ret;
+
+	nfc->sclk = devm_clk_get(dev, "sclk");
+	if (IS_ERR(nfc->sclk)) {
+		dev_err(dev, "failed to retrieve nand_clk\n");
+		ret = PTR_ERR(nfc->sclk);
+		goto out_ahb_clk_unprepare;
+	}
+
+	ret = clk_prepare_enable(nfc->sclk);
+	if (ret)
+		goto out_ahb_clk_unprepare;
+
+	/* Reset NFC */
+	writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RESET,
+	       nfc->regs + NFC_REG_CTL);
+	while (readl(nfc->regs + NFC_REG_CTL) & NFC_RESET)
+		;
+
+	writel(0, nfc->regs + NFC_REG_INT);
+	ret = devm_request_irq(dev, nfc->irq, sunxi_nfc_interrupt,
+			       0, "sunxi-nand", nfc);
+	if (ret)
+		goto out_sclk_unprepare;
+
+	platform_set_drvdata(pdev, nfc);
+
+	writel(0x100, nfc->regs + NFC_REG_TIMING_CTL);
+	writel(0x7ff, nfc->regs + NFC_REG_TIMING_CFG);
+
+	ret = sunxi_nand_chips_init(dev, nfc);
+	if (ret) {
+		dev_err(dev, "failed to init nand chips\n");
+		goto out_sclk_unprepare;
+	}
+
+	return 0;
+
+out_sclk_unprepare:
+	clk_disable_unprepare(nfc->sclk);
+out_ahb_clk_unprepare:
+	clk_disable_unprepare(nfc->ahb_clk);
+
+	return ret;
+}
+
+static const struct of_device_id sunxi_nfc_ids[] = {
+	{ .compatible = "allwinner,sun4i-nand" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
+
+static struct platform_driver sunxi_nfc_driver = {
+	.driver = {
+		.name = "sunxi_nand",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(sunxi_nfc_ids),
+	},
+	.probe = sunxi_nfc_probe,
+};
+module_platform_driver(sunxi_nfc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Boris BREZILLON");
+MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
+MODULE_ALIAS("platform:sunxi_nfc");
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v2 07/14] of: mtd: add documentation for the ONFI NAND timing mode property
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Add documentation for the ONFI NAND timing mode property.

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 Documentation/devicetree/bindings/mtd/nand.txt |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
index 0c962296..75e46f3 100644
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -8,3 +8,8 @@
   E.g. : nand-ecc-level = <4 512>; /* 4 bits / 512 bytes */
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+- onfi,nand-timing-mode: an integer encoding the ONFI timing mode of the NAND
+  chip. This is only used when the chip does not support the ONFI standard.
+  Choose the closest mode fulfilling the NAND chip timings.
+  For a full description of the different timing modes see this document:
+  www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf?
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v2 06/14] of: mtd: add NAND timing mode retrieval support
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Add a function to retrieve NAND timing mode (ONFI timing mode) from a given
DT node.

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 drivers/of/of_mtd.c    |   19 +++++++++++++++++++
 include/linux/of_mtd.h |    8 ++++++++
 2 files changed, 27 insertions(+)

diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c
index e8ced61..63155d4 100644
--- a/drivers/of/of_mtd.c
+++ b/drivers/of/of_mtd.c
@@ -108,3 +108,22 @@ bool of_get_nand_on_flash_bbt(struct device_node *np)
 	return of_property_read_bool(np, "nand-on-flash-bbt");
 }
 EXPORT_SYMBOL_GPL(of_get_nand_on_flash_bbt);
+
+/**
+ * of_get_nand_timings - Get nand timings for the given device_node
+ * @np:	Pointer to the given device_node
+ *
+ * return 0 on success errno other wise
+ */
+int of_get_nand_onfi_timing_mode(struct device_node *np)
+{
+	int err;
+	u32 mode;
+
+	err = of_property_read_u32(np, "onfi,nand-timing-mode", &mode);
+	if (err)
+		return err;
+
+	return mode;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_onfi_timing_mode);
diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h
index 3bd8c3b..eb9fda6 100644
--- a/include/linux/of_mtd.h
+++ b/include/linux/of_mtd.h
@@ -9,6 +9,8 @@
 #ifndef __LINUX_OF_MTD_H
 #define __LINUX_OF_NET_H
 
+#include <linux/mtd/nand.h>
+
 #ifdef CONFIG_OF_MTD
 
 #include <linux/of.h>
@@ -16,6 +18,7 @@ int of_get_nand_ecc_mode(struct device_node *np);
 int of_get_nand_ecc_level(struct device_node *np, u32 *strengh, u32 *blk_size);
 int of_get_nand_bus_width(struct device_node *np);
 bool of_get_nand_on_flash_bbt(struct device_node *np);
+int of_get_nand_onfi_timing_mode(struct device_node *np);
 
 #else /* CONFIG_OF_MTD */
 
@@ -40,6 +43,11 @@ static inline bool of_get_nand_on_flash_bbt(struct device_node *np)
 	return false;
 }
 
+static inline int of_get_nand_onfi_timing_mode(struct device_node *np)
+{
+	return -ENOSYS;
+}
+
 #endif /* CONFIG_OF_MTD */
 
 #endif /* __LINUX_OF_MTD_H */
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v2 05/14] mtd: nand: add ONFI timing mode to nand_timings converter
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>

Add a converter to retrieve NAND timings from an ONFI NAND timing mode.
This only support SDR NAND timings for now.

Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
 drivers/mtd/nand/Makefile       |    2 +-
 drivers/mtd/nand/nand_timings.c |  248 +++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/nand.h        |    4 +
 3 files changed, 253 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/nand/nand_timings.c

diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 542b568..bbea7a6 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -2,7 +2,7 @@
 # linux/drivers/nand/Makefile
 #
 
-obj-$(CONFIG_MTD_NAND)			+= nand.o
+obj-$(CONFIG_MTD_NAND)			+= nand.o nand_timings.o
 obj-$(CONFIG_MTD_NAND_ECC)		+= nand_ecc.o
 obj-$(CONFIG_MTD_NAND_BCH)		+= nand_bch.o
 obj-$(CONFIG_MTD_NAND_IDS)		+= nand_ids.o
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
new file mode 100644
index 0000000..f66fe95
--- /dev/null
+++ b/drivers/mtd/nand/nand_timings.c
@@ -0,0 +1,248 @@
+/*
+ *  Copyright (C) 2014 Boris BREZILLON <b.brezillon.dev@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/mtd/nand.h>
+
+static const struct nand_sdr_timings onfi_sdr_timings[] = {
+	/* Mode 0 */
+	{
+		.tADL_min = 200000,
+		.tALH_min = 20000,
+		.tALS_min = 50000,
+		.tAR_min = 25000,
+		.tCEA_max = 100000,
+		.tCEH_min = 20000,
+		.tCH_min = 20000,
+		.tCHZ_max = 100000,
+		.tCLH_min = 20000,
+		.tCLR_min = 20000,
+		.tCLS_min = 50000,
+		.tCOH_min = 0,
+		.tCS_min = 70000,
+		.tDH_min = 20000,
+		.tDS_min = 40000,
+		.tFEAT_max = 1000000,
+		.tIR_min = 10000,
+		.tITC_max = 1000000,
+		.tRC_min = 100000,
+		.tREA_max = 40000,
+		.tREH_min = 30000,
+		.tRHOH_min = 0,
+		.tRHW_min = 200000,
+		.tRHZ_max = 200000,
+		.tRLOH_min = 0,
+		.tRP_min = 50000,
+		.tRST_max = 250000000000,
+		.tWB_max = 200000,
+		.tRR_min = 40000,
+		.tWC_min = 100000,
+		.tWH_min = 30000,
+		.tWHR_min = 120000,
+		.tWP_min = 50000,
+		.tWW_min = 100000,
+	},
+	/* Mode 1 */
+	{
+		.tADL_min = 100000,
+		.tALH_min = 10000,
+		.tALS_min = 25000,
+		.tAR_min = 10000,
+		.tCEA_max = 45000,
+		.tCEH_min = 20000,
+		.tCH_min = 10000,
+		.tCHZ_max = 50000,
+		.tCLH_min = 10000,
+		.tCLR_min = 10000,
+		.tCLS_min = 25000,
+		.tCOH_min = 15000,
+		.tCS_min = 35000,
+		.tDH_min = 10000,
+		.tDS_min = 20000,
+		.tFEAT_max = 1000000,
+		.tIR_min = 0,
+		.tITC_max = 1000000,
+		.tRC_min = 50000,
+		.tREA_max = 30000,
+		.tREH_min = 15000,
+		.tRHOH_min = 15000,
+		.tRHW_min = 100000,
+		.tRHZ_max = 100000,
+		.tRLOH_min = 0,
+		.tRP_min = 25000,
+		.tRR_min = 20000,
+		.tRST_max = 500000000,
+		.tWB_max = 100000,
+		.tWC_min = 45000,
+		.tWH_min = 15000,
+		.tWHR_min = 80000,
+		.tWP_min = 25000,
+		.tWW_min = 100000,
+	},
+	/* Mode 2 */
+	{
+		.tADL_min = 100000,
+		.tALH_min = 10000,
+		.tALS_min = 15000,
+		.tAR_min = 10000,
+		.tCEA_max = 30000,
+		.tCEH_min = 20000,
+		.tCH_min = 10000,
+		.tCHZ_max = 50000,
+		.tCLH_min = 10000,
+		.tCLR_min = 10000,
+		.tCLS_min = 15000,
+		.tCOH_min = 15000,
+		.tCS_min = 25000,
+		.tDH_min = 5000,
+		.tDS_min = 15000,
+		.tFEAT_max = 1000000,
+		.tIR_min = 0,
+		.tITC_max = 1000000,
+		.tRC_min = 35000,
+		.tREA_max = 25000,
+		.tREH_min = 15000,
+		.tRHOH_min = 15000,
+		.tRHW_min = 100000,
+		.tRHZ_max = 100000,
+		.tRLOH_min = 0,
+		.tRR_min = 20000,
+		.tRST_max = 500000000,
+		.tWB_max = 100000,
+		.tRP_min = 17000,
+		.tWC_min = 35000,
+		.tWH_min = 15000,
+		.tWHR_min = 80000,
+		.tWP_min = 17000,
+		.tWW_min = 100000,
+	},
+	/* Mode 3 */
+	{
+		.tADL_min = 100000,
+		.tALH_min = 5000,
+		.tALS_min = 10000,
+		.tAR_min = 10000,
+		.tCEA_max = 25000,
+		.tCEH_min = 20000,
+		.tCH_min = 5000,
+		.tCHZ_max = 50000,
+		.tCLH_min = 5000,
+		.tCLR_min = 10000,
+		.tCLS_min = 10000,
+		.tCOH_min = 15000,
+		.tCS_min = 25000,
+		.tDH_min = 5000,
+		.tDS_min = 10000,
+		.tFEAT_max = 1000000,
+		.tIR_min = 0,
+		.tITC_max = 1000000,
+		.tRC_min = 30000,
+		.tREA_max = 20000,
+		.tREH_min = 10000,
+		.tRHOH_min = 15000,
+		.tRHW_min = 100000,
+		.tRHZ_max = 100000,
+		.tRLOH_min = 0,
+		.tRP_min = 15000,
+		.tRR_min = 20000,
+		.tRST_max = 500000000,
+		.tWB_max = 100000,
+		.tWC_min = 30000,
+		.tWH_min = 10000,
+		.tWHR_min = 80000,
+		.tWP_min = 15000,
+		.tWW_min = 100000,
+	},
+	/* Mode 4 */
+	{
+		.tADL_min = 70000,
+		.tALH_min = 5000,
+		.tALS_min = 10000,
+		.tAR_min = 10000,
+		.tCEA_max = 25000,
+		.tCEH_min = 20000,
+		.tCH_min = 5000,
+		.tCHZ_max = 30000,
+		.tCLH_min = 5000,
+		.tCLR_min = 10000,
+		.tCLS_min = 10000,
+		.tCOH_min = 15000,
+		.tCS_min = 20000,
+		.tDH_min = 5000,
+		.tDS_min = 10000,
+		.tFEAT_max = 1000000,
+		.tIR_min = 0,
+		.tITC_max = 1000000,
+		.tRC_min = 25000,
+		.tREA_max = 20000,
+		.tREH_min = 10000,
+		.tRHOH_min = 15000,
+		.tRHW_min = 100000,
+		.tRHZ_max = 100000,
+		.tRLOH_min = 5000,
+		.tRP_min = 12000,
+		.tRR_min = 20000,
+		.tRST_max = 500000000,
+		.tWB_max = 100000,
+		.tWC_min = 25000,
+		.tWH_min = 10000,
+		.tWHR_min = 80000,
+		.tWP_min = 12000,
+		.tWW_min = 100000,
+	},
+	/* Mode 5 */
+	{
+		.tADL_min = 70000,
+		.tALH_min = 5000,
+		.tALS_min = 10000,
+		.tAR_min = 10000,
+		.tCEA_max = 25000,
+		.tCEH_min = 20000,
+		.tCH_min = 5000,
+		.tCHZ_max = 30000,
+		.tCLH_min = 5000,
+		.tCLR_min = 10000,
+		.tCLS_min = 10000,
+		.tCOH_min = 15000,
+		.tCS_min = 15000,
+		.tDH_min = 5000,
+		.tDS_min = 7000,
+		.tFEAT_max = 1000000,
+		.tIR_min = 0,
+		.tITC_max = 1000000,
+		.tRC_min = 20000,
+		.tREA_max = 16000,
+		.tREH_min = 7000,
+		.tRHOH_min = 15000,
+		.tRHW_min = 100000,
+		.tRHZ_max = 100000,
+		.tRLOH_min = 5000,
+		.tRP_min = 10000,
+		.tRR_min = 20000,
+		.tRST_max = 500000000,
+		.tWB_max = 100000,
+		.tWC_min = 20000,
+		.tWH_min = 7000,
+		.tWHR_min = 80000,
+		.tWP_min = 10000,
+		.tWW_min = 100000,
+	},
+};
+
+/**
+ * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
+ * timings according to the given ONFI timing mode
+ * @mode: ONFI timing mode
+ */
+const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
+{
+	if (mode < 0 || mode > ARRAY_SIZE(onfi_sdr_timings))
+		return ERR_PTR(-EINVAL);
+
+	return &onfi_sdr_timings[mode];
+}
+EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 67f0829..c70e0a3 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -806,6 +806,7 @@ static inline bool nand_is_slc(struct nand_chip *chip)
 	return chip->bits_per_cell == 1;
 }
 
+
 /**
  * struct nand_sdr_timings - SDR NAND chip timings
  *
@@ -854,4 +855,7 @@ struct nand_sdr_timings {
 	u32 tWW_min;
 };
 
+/* convert an ONFI timing mode to its timing characteristics. */
+const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
+
 #endif /* __LINUX_MTD_NAND_H */
-- 
1.7.9.5

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox