* [PATCH] ARM: keystone: dts: disable "msmcsram" clock
From: Santosh Shilimkar @ 2014-01-30 14:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52EA5A8F.7070107@ti.com>
On Thursday 30 January 2014 08:58 AM, Ivan Khoronzhuk wrote:
> Ok. I will delete node for this clock from DT and send v1
>
Sorry for the html reply first of all. That node should never have
been actually added since the clock is not suppose to be touched even
in low power states. Change log should say something like this ...
"MSMC is the coherency interconnect and all the coherent masters are
connected to it including devices which are not under Linux OS control.
MSMC clock should not be toched even in low power states."
So drop the clock node o.w without 'clk_ignore_unused' will disable
the clock leading to system stall.
I wil try get these in rc's since its a bug fix
Regards,
Santosh
^ permalink raw reply
* NFS client broken in Linus' tip
From: Russell King - ARM Linux @ 2014-01-30 14:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <960A8F94-BDD4-4ED0-95EC-0D71D4AC27E7@primarydata.com>
On Thu, Jan 30, 2014 at 09:17:00AM -0500, Trond Myklebust wrote:
>
> On Jan 30, 2014, at 9:08, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
>
> > I just booted Linus' tip (plus a few other patches to imx-drm and imx
> > code), and stumbled into this interesting scenario:
> >
> > # touch test
> > touch: cannot touch `test': Operation not supported
> >
> > I also tried mkdir and mknod, all result in the same error. Hard and
> > symlinks links are creatable.
> >
> > However, I can chmod existing files and rename them. Files can also be
> > deleted, and the combination of this has left me without a /etc/mtab !
> >
> > The machine is a iMX6 based ARM, running root-nfs, which was mounted via
> > ubuntu's initramfs (so not using the kernel's built-in root-nfs.)
> >
> > /proc/mounts for the root mount gives:
> > 192.168.1.123:/var/boot/ci / nfs rw,relatime,vers=3,rsize=65536,wsize=65536,namlen=255,hard,nolock,proto=tcp,port=2049,timeo=7,retrans=10,sec=sys,local_lock=all,addr=192.168.1.123 0 0
> >
> > CONFIG_NFS_FS=y
> > CONFIG_NFS_V2=y
> > CONFIG_NFS_V3=y
> > CONFIG_NFS_V3_ACL=y
> > CONFIG_NFS_V4=y
> > # CONFIG_NFS_SWAP is not set
> > # CONFIG_NFS_V4_1 is not set
> > CONFIG_ROOT_NFS=y
> > # CONFIG_NFS_USE_LEGACY_DNS is not set
> > CONFIG_NFS_USE_KERNEL_DNS=y
> > # CONFIG_NFSD is not set
> > CONFIG_LOCKD=y
> > CONFIG_LOCKD_V4=y
> > CONFIG_NFS_ACL_SUPPORT=y
> > CONFIG_NFS_COMMON=y
> > CONFIG_SUNRPC=y
> > CONFIG_SUNRPC_GSS=y
> >
> > tcpdumping, I see:
> >
> > 13:59:51.713523 IP 192.168.1.252.1341245608 > 192.168.1.123.2049: 132 lookup fh Unknown/010007011040840000000000CC238FC8FBA0475D9D9F8356B4C44166CDC38700 "test"
> > 13:59:51.714345 IP 192.168.1.123.2049 > 192.168.1.252.1341245608: reply ok 120 lookup ERROR: No such file or directory
> > 13:59:51.751303 IP 192.168.1.252.797 > 192.168.1.123.nfs: . ack 3381 win 2625 <nop,nop,timestamp 474136 3431312924>
> >
> > which is the only NFS packet(s) I see which mention "test".
> >
> > and stracing touch:
> >
> > open("test", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0666) = -1 EOPNOTSUPP (Operation not supported)
> > utimensat(AT_FDCWD, "test", NULL, 0) = -1 ENOENT (No such file or directory)
> > write(2, "touch: ", 7touch: ) = 7
> > write(2, "cannot touch `test'", 19cannot touch `test') = 19
> > write(2, ": Operation not supported", 25: Operation not supported) = 25
> > write(2, "\n", 1
> > ) = 1
> >
> > I think it's down to this:
> >
> > commit 013cdf1088d7235da9477a2375654921d9b9ba9f
> > Author: Christoph Hellwig <hch@infradead.org>
> > Date: Fri Dec 20 05:16:53 2013 -0800
> >
> > nfs: use generic posix ACL infrastructure for v3 Posix ACLs
> >
> > This causes a small behaviour change in that we don't bother to set
> > ACLs on file creation if the mode bit can express the access permissions
> > fully, and thus behaving identical to local filesystems.
> >
> > Signed-off-by: Christoph Hellwig <hch@lst.de>
> > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> >
> > which adds:
> >
> > + status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
> > + if (status)
> > + goto out;
>
> Right, this should clearly not cause nfs4_proc_create to fail if it
> returns EOPNOTSUPP.
NFS3 :)
> > into nfs3_proc_create(), but this ends up calling down into nfs3_get_acl(),
> > which does this:
> >
> > if (!nfs_server_capable(inode, NFS_CAP_ACLS))
> > return ERR_PTR(-EOPNOTSUPP);
>
> Just for completeness sake: is the server you were running against supposed to support POSIX acls?
The server is an old 3.1.8 kernel with this NFS config:
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_FSCACHE is not set
CONFIG_NFSD=m
CONFIG_NFSD_V3=y
# CONFIG_NFSD_V3_ACL is not set
# CONFIG_NFSD_V4 is not set
CONFIG_LOCKD=m
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
which has worked fine with NFS clients for the last 1800 odd days... until
now.
--
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up. Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
^ permalink raw reply
* NFS client broken in Linus' tip
From: Russell King - ARM Linux @ 2014-01-30 14:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140130141405.GA23985@infradead.org>
On Thu, Jan 30, 2014 at 06:14:05AM -0800, Christoph Hellwig wrote:
> On Thu, Jan 30, 2014 at 02:08:34PM +0000, Russell King - ARM Linux wrote:
> > into nfs3_proc_create(), but this ends up calling down into nfs3_get_acl(),
> > which does this:
> >
> > if (!nfs_server_capable(inode, NFS_CAP_ACLS))
> > return ERR_PTR(-EOPNOTSUPP);
>
> Does replacing that return with a
>
> return NULL;
>
> fix the issue for you?
Yes and no. I still end up with an empty /etc/mtab, but the file now
exists. However, I can create and echo data into /etc/mtab, but it seems
that can't happen at boot time.
I also find that kerberos doesn't work - again, it's weird - I can create
the file which kerberos is trying to create in /var/tmp (which is also on
the root nfs) manually, but when the kerberos daemons try to create it,
it fails with -EOPNOTSUPP. The kerberos daemon is running as uid 0 at
that point (I don't know about the other uids/gids though since I wasn't
able to catch them in the strace.)
--
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up. Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
^ permalink raw reply
* [RFC PATCH V3 0/4] APM X-Gene PCIe controller
From: Arnd Bergmann @ 2014-01-30 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACoXjc=LSrLK=kd9GJoHWJovVDC+TfH2bZO-2Ht9jMoBrL9eag@mail.gmail.com>
On Thursday 30 January 2014, Tanmay Inamdar wrote:
> >
> > When you repost, please make sure you fix whatever problem is
> > preventing your email from appearing on the vger mailing lists. I
> > won't apply things that haven't appeared on the linux-pci list,
> > because that list is the opportunity for other people to review them.
> >
> You are absolutely right. If the patches are not reaching mailing
> list, they should not appear on archive list as well. However I am
> seeing my patches recorded on archives. So I am not sure if they are
> actually getting dropped on linux-pci or any other mailing list.
>
> http://www.spinics.net/lists/linux-pci/msg28198.html
> http://article.gmane.org/gmane.linux.kernel.pci/28442/match=tanmay+inamdar
Very strange. I can also confirm that I received the patches through
the linux-arm-kernel and devicetree mailing lists without problems.
Arnd
^ permalink raw reply
* [RFC PATCH V3 0/4] APM X-Gene PCIe controller
From: Arnd Bergmann @ 2014-01-30 14:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390599168-13150-1-git-send-email-tinamdar@apm.com>
On Friday 24 January 2014, Tanmay Inamdar wrote:
> This patch adds support for AppliedMicro X-Gene PCIe host controller. The
> driver is tested on X-Gene platform with different gen1/2/3 PCIe endpoint
> cards.
>
> X-Gene PCIe controller driver has depedency on the pcie arch support for
> arm64. The arm64 pcie arch support is not yet part of mainline Linux kernel
> and approach for arch support is under discussion with arm64 maintainers.
> The reference patch can be found here --> https://lkml.org/lkml/2013/10/23/244
>
> If someone wishes to test PCIe on X-Gene, arch support patch must be applied
> before the patches in this patch set.
This is starting to look really good now. I have a few small comments left,
otherwise it can get merged. As mentioned in one of my review comments, it
would be good to have the arch support patch posted along with the driver.
Arnd
^ permalink raw reply
* NFS client broken in Linus' tip
From: Trond Myklebust @ 2014-01-30 14:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140130140834.GW15937@n2100.arm.linux.org.uk>
On Jan 30, 2014, at 9:08, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> I just booted Linus' tip (plus a few other patches to imx-drm and imx
> code), and stumbled into this interesting scenario:
>
> # touch test
> touch: cannot touch `test': Operation not supported
>
> I also tried mkdir and mknod, all result in the same error. Hard and
> symlinks links are creatable.
>
> However, I can chmod existing files and rename them. Files can also be
> deleted, and the combination of this has left me without a /etc/mtab !
>
> The machine is a iMX6 based ARM, running root-nfs, which was mounted via
> ubuntu's initramfs (so not using the kernel's built-in root-nfs.)
>
> /proc/mounts for the root mount gives:
> 192.168.1.123:/var/boot/ci / nfs rw,relatime,vers=3,rsize=65536,wsize=65536,namlen=255,hard,nolock,proto=tcp,port=2049,timeo=7,retrans=10,sec=sys,local_lock=all,addr=192.168.1.123 0 0
>
> CONFIG_NFS_FS=y
> CONFIG_NFS_V2=y
> CONFIG_NFS_V3=y
> CONFIG_NFS_V3_ACL=y
> CONFIG_NFS_V4=y
> # CONFIG_NFS_SWAP is not set
> # CONFIG_NFS_V4_1 is not set
> CONFIG_ROOT_NFS=y
> # CONFIG_NFS_USE_LEGACY_DNS is not set
> CONFIG_NFS_USE_KERNEL_DNS=y
> # CONFIG_NFSD is not set
> CONFIG_LOCKD=y
> CONFIG_LOCKD_V4=y
> CONFIG_NFS_ACL_SUPPORT=y
> CONFIG_NFS_COMMON=y
> CONFIG_SUNRPC=y
> CONFIG_SUNRPC_GSS=y
>
> tcpdumping, I see:
>
> 13:59:51.713523 IP 192.168.1.252.1341245608 > 192.168.1.123.2049: 132 lookup fh Unknown/010007011040840000000000CC238FC8FBA0475D9D9F8356B4C44166CDC38700 "test"
> 13:59:51.714345 IP 192.168.1.123.2049 > 192.168.1.252.1341245608: reply ok 120 lookup ERROR: No such file or directory
> 13:59:51.751303 IP 192.168.1.252.797 > 192.168.1.123.nfs: . ack 3381 win 2625 <nop,nop,timestamp 474136 3431312924>
>
> which is the only NFS packet(s) I see which mention "test".
>
> and stracing touch:
>
> open("test", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0666) = -1 EOPNOTSUPP (Operation not supported)
> utimensat(AT_FDCWD, "test", NULL, 0) = -1 ENOENT (No such file or directory)
> write(2, "touch: ", 7touch: ) = 7
> write(2, "cannot touch `test'", 19cannot touch `test') = 19
> write(2, ": Operation not supported", 25: Operation not supported) = 25
> write(2, "\n", 1
> ) = 1
>
> I think it's down to this:
>
> commit 013cdf1088d7235da9477a2375654921d9b9ba9f
> Author: Christoph Hellwig <hch@infradead.org>
> Date: Fri Dec 20 05:16:53 2013 -0800
>
> nfs: use generic posix ACL infrastructure for v3 Posix ACLs
>
> This causes a small behaviour change in that we don't bother to set
> ACLs on file creation if the mode bit can express the access permissions
> fully, and thus behaving identical to local filesystems.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
>
> which adds:
>
> + status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
> + if (status)
> + goto out;
Right, this should clearly not cause nfs4_proc_create to fail if it returns EOPNOTSUPP.
> into nfs3_proc_create(), but this ends up calling down into nfs3_get_acl(),
> which does this:
>
> if (!nfs_server_capable(inode, NFS_CAP_ACLS))
> return ERR_PTR(-EOPNOTSUPP);
Just for completeness sake: is the server you were running against supposed to support POSIX acls?
--
Trond Myklebust
Linux NFS client maintainer
^ permalink raw reply
* [RFC PATCH V3 1/4] pci: APM X-Gene PCIe controller driver
From: Arnd Bergmann @ 2014-01-30 14:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390599168-13150-2-git-send-email-tinamdar@apm.com>
On Friday 24 January 2014, Tanmay Inamdar wrote:
> +static void xgene_pcie_fixup_bridge(struct pci_dev *dev)
> +{
> + int i;
> +
> + /* Hide the PCI host BARs from the kernel as their content doesn't
> + * fit well in the resource management
> + */
> + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
> + dev->resource[i].start = dev->resource[i].end = 0;
> + dev->resource[i].flags = 0;
> + }
> + dev_info(&dev->dev, "Hiding X-Gene pci host bridge resources %s\n",
> + pci_name(dev));
> +}
> +DECLARE_PCI_FIXUP_HEADER(XGENE_PCIE_VENDORID, XGENE_PCIE_DEVICEID,
> + xgene_pcie_fixup_bridge);
Shouldn't this be gone now that the host bridge is correctly shown
at the domain root?
> +static int xgene_pcie_setup(int nr, struct pci_sys_data *sys)
> +{
> + struct xgene_pcie_port *pp = sys->private_data;
> + struct resource *io = &pp->realio;
> +
> + io->start = sys->domain * SZ_64K;
> + io->end = io->start + SZ_64K;
> + io->flags = pp->io.res.flags;
> + io->name = "PCI IO";
> + pci_ioremap_io(io->start, pp->io.res.start);
> +
> + pci_add_resource_offset(&sys->resources, io, sys->io_offset);
> + sys->mem_offset = pp->mem.res.start - pp->mem.pci_addr;
> + pci_add_resource_offset(&sys->resources, &pp->mem.res,
> + sys->mem_offset);
> + return 1;
> +}
Thanks for bringing back the I/O space handling.
You don't seem to set sys->io_offset anywhere, but each of the
ports listed in your DT starts a local bus I/O register range
at port 0.
AFAICT, you need to add (somewhere)
sys->io_offset = pp->realio.start - pp->io.pci_addr;
but there could be something else missing. You clearly haven't
tested if the I/O space actually works.
If you want to try out the I/O space, I'd suggest using an Intel
e1000 network card, which has both memory and i/o space. There
is a patch at http://www.spinics.net/lists/linux-pci/msg27684.html
that lets you check the I/O registers on it, or you can go
through /dev/port from user space.
I also haven't seen your patch that adds pci_ioremap_io() for
arm64. It would be helpful to keep it in the same patch
series, since it won't build without this patch.
Arnd
^ permalink raw reply
* NFS client broken in Linus' tip
From: Christoph Hellwig @ 2014-01-30 14:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140130140834.GW15937@n2100.arm.linux.org.uk>
On Thu, Jan 30, 2014 at 02:08:34PM +0000, Russell King - ARM Linux wrote:
> into nfs3_proc_create(), but this ends up calling down into nfs3_get_acl(),
> which does this:
>
> if (!nfs_server_capable(inode, NFS_CAP_ACLS))
> return ERR_PTR(-EOPNOTSUPP);
Does replacing that return with a
return NULL;
fix the issue for you?
^ permalink raw reply
* [RFC PATCH V3 2/4] arm64: dts: APM X-Gene PCIe device tree nodes
From: Arnd Bergmann @ 2014-01-30 14:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390599168-13150-3-git-send-email-tinamdar@apm.com>
On Friday 24 January 2014, Tanmay Inamdar wrote:
> + pcie3: pcie at 1f500000 {
> + reg-names = "csr", "cfg";
> + ranges = <0x01000000 0x0 0x00000000 0xa0 0x00000000 0x0 0x00010000 /* mem */
> + 0x02000000 0x0 0x10000000 0xa0 0x10000000 0x0 0x80000000>; /* io */
The two comments are wrong for this instance.
Arnd
^ permalink raw reply
* NFS client broken in Linus' tip
From: Russell King - ARM Linux @ 2014-01-30 14:08 UTC (permalink / raw)
To: linux-arm-kernel
I just booted Linus' tip (plus a few other patches to imx-drm and imx
code), and stumbled into this interesting scenario:
# touch test
touch: cannot touch `test': Operation not supported
I also tried mkdir and mknod, all result in the same error. Hard and
symlinks links are creatable.
However, I can chmod existing files and rename them. Files can also be
deleted, and the combination of this has left me without a /etc/mtab !
The machine is a iMX6 based ARM, running root-nfs, which was mounted via
ubuntu's initramfs (so not using the kernel's built-in root-nfs.)
/proc/mounts for the root mount gives:
192.168.1.123:/var/boot/ci / nfs rw,relatime,vers=3,rsize=65536,wsize=65536,namlen=255,hard,nolock,proto=tcp,port=2049,timeo=7,retrans=10,sec=sys,local_lock=all,addr=192.168.1.123 0 0
CONFIG_NFS_FS=y
CONFIG_NFS_V2=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
# CONFIG_NFS_SWAP is not set
# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFS_USE_LEGACY_DNS is not set
CONFIG_NFS_USE_KERNEL_DNS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_ACL_SUPPORT=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
tcpdumping, I see:
13:59:51.713523 IP 192.168.1.252.1341245608 > 192.168.1.123.2049: 132 lookup fh Unknown/010007011040840000000000CC238FC8FBA0475D9D9F8356B4C44166CDC38700 "test"
13:59:51.714345 IP 192.168.1.123.2049 > 192.168.1.252.1341245608: reply ok 120 lookup ERROR: No such file or directory
13:59:51.751303 IP 192.168.1.252.797 > 192.168.1.123.nfs: . ack 3381 win 2625 <nop,nop,timestamp 474136 3431312924>
which is the only NFS packet(s) I see which mention "test".
and stracing touch:
open("test", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0666) = -1 EOPNOTSUPP (Operation not supported)
utimensat(AT_FDCWD, "test", NULL, 0) = -1 ENOENT (No such file or directory)
write(2, "touch: ", 7touch: ) = 7
write(2, "cannot touch `test'", 19cannot touch `test') = 19
write(2, ": Operation not supported", 25: Operation not supported) = 25
write(2, "\n", 1
) = 1
I think it's down to this:
commit 013cdf1088d7235da9477a2375654921d9b9ba9f
Author: Christoph Hellwig <hch@infradead.org>
Date: Fri Dec 20 05:16:53 2013 -0800
nfs: use generic posix ACL infrastructure for v3 Posix ACLs
This causes a small behaviour change in that we don't bother to set
ACLs on file creation if the mode bit can express the access permissions
fully, and thus behaving identical to local filesystems.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
which adds:
+ status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
+ if (status)
+ goto out;
into nfs3_proc_create(), but this ends up calling down into nfs3_get_acl(),
which does this:
if (!nfs_server_capable(inode, NFS_CAP_ACLS))
return ERR_PTR(-EOPNOTSUPP);
--
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up. Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
^ permalink raw reply
* [PATCH] ARM: keystone: dts: disable "msmcsram" clock
From: Ivan Khoronzhuk @ 2014-01-30 13:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <448912EABC71F84BBCADFD3C67C4BE52A0B4B6@DBDE04.ent.ti.com>
Ok. I will delete node for this clock from DT and send v1
On 01/30/2014 03:25 PM, Shilimkar, Santosh wrote:
> Disable is not good idea since it conveys wrong info....
>
> Hyperlink case was different.
>
> Sent from my Android phone using TouchDown (www.nitrodesk.com)
>
> -----Original Message-----
> *From:* Khoronzhuk, Ivan [ivan.khoronzhuk at ti.com]
> *Received:* Thursday, 30 Jan 2014, 6:45am
> *To:* robh+dt at kernel.org [robh+dt at kernel.org]; galak at codeaurora.org
> [galak at codeaurora.org]
> *CC:* pawel.moll at arm.com [pawel.moll at arm.com]; mark.rutland at arm.com
> [mark.rutland at arm.com]; ijc+devicetree at hellion.org.uk
> [ijc+devicetree at hellion.org.uk]; linux at arm.linux.org.uk
> [linux at arm.linux.org.uk]; devicetree at vger.kernel.org
> [devicetree at vger.kernel.org]; linux-arm-kernel at lists.infradead.org
> [linux-arm-kernel at lists.infradead.org]; linux-kernel at vger.kernel.org
> [linux-kernel at vger.kernel.org]; Shilimkar, Santosh [santosh.shilimkar at ti.com];
> Khoronzhuk, Ivan [ivan.khoronzhuk at ti.com]
> *Subject:* [PATCH] ARM: keystone: dts: disable "msmcsram" clock
>
> At late init all unused clocks are disabled. So clocks that were not
> get before will be gated. In Keysone 2 SoC we have at least one
> necessary clock that is not used by any driver - "msmcsram". This
> clock is necessary, because it supplies the Multicore Shared Memory
> Controller (MSMC). The MSMC provides memory protection for accesses to
> the MSMC SRAM and DDR3 memory from system masters. It also manages
> traffic among mastering peripherals and the EMIF.
>
> This means that MSMC clock is always needed by SoC and cannot be gated.
> It is only one from necessary clocks that was not used by any driver.
> So to avoid its gating at late init we have to disable it in DT.
>
> Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
> ---
> arch/arm/boot/dts/keystone-clocks.dtsi | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm/boot/dts/keystone-clocks.dtsi
> b/arch/arm/boot/dts/keystone-clocks.dtsi
> index 2363593..e7aea2e 100644
> --- a/arch/arm/boot/dts/keystone-clocks.dtsi
> +++ b/arch/arm/boot/dts/keystone-clocks.dtsi
> @@ -332,6 +332,7 @@ clocks {
> compatible = "ti,keystone,psc-clock";
> clocks = <&chipclk1>;
> clock-output-names = "msmcsram";
> + status = "disabled";
> reg = <0x02350038 0xb00>, <0x0235001c 0x400>;
> reg-names = "control", "domain";
> domain-id = <7>;
> --
> 1.8.3.2
>
^ permalink raw reply
* [PATCH] clk: keystone: gate: fix clk_init_data initialization
From: Ivan Khoronzhuk @ 2014-01-30 13:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <448912EABC71F84BBCADFD3C67C4BE52A0B4EB@DBDE04.ent.ti.com>
Yes. As result the clk->flag field contains garbage. In my case it leads
that flag CLK_IGNORE_UNUSED is set for most of clocks. As result a bunch
of unused clocks cannot be disabled.
On 01/30/2014 03:26 PM, Shilimkar, Santosh wrote:
> Can u capture the issue withiout this fix?
>
> Sent from my Android phone using TouchDown (www.nitrodesk.com)
>
> -----Original Message-----
> *From:* Khoronzhuk, Ivan [ivan.khoronzhuk at ti.com]
> *Received:* Thursday, 30 Jan 2014, 6:37am
> *To:* Shilimkar, Santosh [santosh.shilimkar at ti.com]
> *CC:* mturquette at linaro.org [mturquette at linaro.org];
> linux-arm-kernel at lists.infradead.org [linux-arm-kernel at lists.infradead.org];
> linux-kernel at vger.kernel.org [linux-kernel at vger.kernel.org]; Khoronzhuk, Ivan
> [ivan.khoronzhuk at ti.com]
> *Subject:* [PATCH] clk: keystone: gate: fix clk_init_data initialization
>
> In clk_register_psc() function clk_init_data struct is allocated
> in the stack. All members of this struct should be initialized
> before using otherwise it will contain garbage. So initialize flags
> in this structure too.
>
> Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
> ---
> drivers/clk/keystone/gate.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c
> index 17a5983..86f1e36 100644
> --- a/drivers/clk/keystone/gate.c
> +++ b/drivers/clk/keystone/gate.c
> @@ -179,6 +179,7 @@ static struct clk *clk_register_psc(struct device *dev,
>
> init.name = name;
> init.ops = &clk_psc_ops;
> + init.flags = 0;
> init.parent_names = (parent_name ? &parent_name : NULL);
> init.num_parents = (parent_name ? 1 : 0);
>
> --
> 1.8.3.2
>
^ permalink raw reply
* [RFC PATCH pre-v3 07/14] of: mtd: add documentation for the ONFI NAND timing mode property
From: Boris BREZILLON @ 2014-01-30 13:46 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>
---
Changes since v2:
- fix description of the nand-timing-mode property: the mode property is
a mask containing all supported modes, each mode is encoded as a bit
position
Documentation/devicetree/bindings/mtd/nand.txt | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
index 0c962296..60c7112 100644
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -8,3 +8,10 @@
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 supported ONFI timing modes of
+ the NAND chip. Each supported mode is represented as a bit position (i.e. :
+ mode 0 and 1 => (1 << 0) | (1 << 1) = 0x3).
+ This is only used when the chip does not support the ONFI standard.
+ The last bit set represent 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
* [PATCH v2 1/6] idle: move the cpuidle entry point to the generic idle loop
From: Daniel Lezcano @ 2014-01-30 13:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.11.1401300021530.1652@knanqh.ubzr>
On 01/30/2014 06:28 AM, Nicolas Pitre wrote:
> On Thu, 30 Jan 2014, Preeti U Murthy wrote:
>
>> Hi Nicolas,
>>
>> On 01/30/2014 02:01 AM, Nicolas Pitre wrote:
>>> On Wed, 29 Jan 2014, Nicolas Pitre wrote:
>>>
>>>> In order to integrate cpuidle with the scheduler, we must have a better
>>>> proximity in the core code with what cpuidle is doing and not delegate
>>>> such interaction to arch code.
>>>>
>>>> Architectures implementing arch_cpu_idle() should simply enter
>>>> a cheap idle mode in the absence of a proper cpuidle driver.
>>>>
>>>> Signed-off-by: Nicolas Pitre <nico@linaro.org>
>>>> Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
>>>
>>> As mentioned in my reply to Olof's comment on patch #5/6, here's a new
>>> version of this patch adding the safety local_irq_enable() to the core
>>> code.
>>>
>>> ----- >8
>>>
>>> From: Nicolas Pitre <nicolas.pitre@linaro.org>
>>> Subject: idle: move the cpuidle entry point to the generic idle loop
>>>
>>> In order to integrate cpuidle with the scheduler, we must have a better
>>> proximity in the core code with what cpuidle is doing and not delegate
>>> such interaction to arch code.
>>>
>>> Architectures implementing arch_cpu_idle() should simply enter
>>> a cheap idle mode in the absence of a proper cpuidle driver.
>>>
>>> In both cases i.e. whether it is a cpuidle driver or the default
>>> arch_cpu_idle(), the calling convention expects IRQs to be disabled
>>> on entry and enabled on exit. There is a warning in place already but
>>> let's add a forced IRQ enable here as well. This will allow for
>>> removing the forced IRQ enable some implementations do locally and
>>
>> Why would this patch allow for removing the forced IRQ enable that are
>> being done on some archs in arch_cpu_idle()? Isn't this patch expecting
>> the default arch_cpu_idle() to have re-enabled the interrupts after
>> exiting from the default idle state? Its supposed to only catch faulty
>> cpuidle drivers that haven't enabled IRQs on exit from idle state but
>> are expected to have done so, isn't it?
>
> Exact. However x86 currently does this:
>
> if (cpuidle_idle_call())
> x86_idle();
> else
> local_irq_enable();
>
> So whenever cpuidle_idle_call() is successful then IRQs are
> unconditionally enabled whether or not the underlying cpuidle driver has
> properly done it or not. And the reason is that some of the x86 cpuidle
> do fail to enable IRQs before returning.
>
> So the idea is to get rid of this unconditional IRQ enabling and let the
> core issue a warning instead (as well as enabling IRQs to allow the
> system to run).
But what I don't get with your comment is the local_irq_enable is done
from the cpuidle common framework in 'cpuidle_enter_state' it is not
done from the arch specific backend cpuidle driver.
So the code above could be:
if (cpuidle_idle_call())
x86_idle();
without the else section, this local_irq_enable is pointless. Or may be
I missed something ?
--
<http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Extending OPP bindings
From: Sudeep Holla @ 2014-01-30 13:43 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
I am looking into a couple shortcomings in the current OPP bindings and
how to address them. Feel free to add to the list if you think of any more
issues that needs to be addressed or if and how any problem mentioned below
can be handled with the existing bindings.
1. indexing: currently there are no indices in the operating-points.
It's assumed that the list is either in ascending or descending
order of frequency but not explicit in the binding document.
There are arch/arm/boot/dts/* files with opps in both styles.
Few other bindings like thermal defines bindings like
cooling-{min,max}-state assuming some order which is broken IMO.
One such use-case that came up recently[0] is the c-state latencies
which could be different for each OPP. It would be good if the
latencies are specified with the indices to OPP table to avoid
inconsistency between the bindings.
It's mainly to avoid issues due to inconsistency and duplication
on data(frequency) in multiple bindings requiring it.
Once we have indices to each on the OPP entries, then other binding
using it can refer to OPP with phandle and OPP index/specifier pairs
very similar to clock provider and consumer.
2. sharing opps: I have tried to address this issue previously[1] but unable
to conclude yet on this.
3. latencies(*): currently the latency that the CPU/memory access is unavailable
during an OPP transition is generic i.e. same from any OPP to any
other OPP. Does it make sense to have this per-OPP entry ?
4. power(*): A measure of maximum power dissipation in an OPP state.
This might be useful measure for power aware scheduling ?
(*) these are already part of P-state in ACPI(refer struct acpi_processor_px
in include/acpi/processor.h)
Apart from these I have seen on-going discussion for Samsung Exynos CPUFreq[2]
which might have some feedback for OPP bindings.
It would be good to consolidate the shortcomings found so far, that could
help in extending the current OPP bindings.
Regards,
Sudeep
[0] http://www.spinics.net/lists/arm-kernel/msg301971.html
[1] http://www.spinics.net/lists/cpufreq/msg07911.html
[2] http://www.spinics.net/lists/cpufreq/msg09169.html
^ permalink raw reply
* [RFC PATCH pre-v3 13/14] mtd: nand: add sunxi HW ECC support
From: Boris BREZILLON @ 2014-01-30 13:41 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 1014b2a..b90268f 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_set_timings(struct sunxi_nand_chip *chip,
const struct nand_sdr_timings *timings)
{
@@ -504,6 +629,144 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
return sunxi_nand_chip_set_timings(chip, timings);
}
+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)
{
@@ -512,8 +775,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;
@@ -586,7 +847,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;
@@ -602,16 +862,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 pre-v3 08/14] mtd: nand: add sunxi NAND flash controller support
From: Boris BREZILLON @ 2014-01-30 13:39 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>
---
Hello,
This version fixes a bug in the R/B GPIO config block.
The timing config order is now respected, but I'll wait for Jason work
regarding timing config in NAND core code before posting the 3rd version
of this series.
Best Regards,
Boris
Changes since v2:
- fix R/B GPIO retrieval/config bug
- fix timings configuration order (set mode 0 -> scan -> set best supported
mode)
drivers/mtd/nand/Kconfig | 6 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/sunxi_nand.c | 758 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 765 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..1014b2a
--- /dev/null
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -0,0 +1,758 @@
+/*
+ * 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_set_timings(struct sunxi_nand_chip *chip,
+ const struct nand_sdr_timings *timings)
+{
+ u32 min_clk_period = 0;
+
+ /* 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 < 1000)
+ min_clk_period = 1000;
+
+ min_clk_period /= 1000;
+ chip->clk_rate = (2 * 1000000000) / min_clk_period;
+
+ /* TODO: configure T16-T19 */
+
+ return 0;
+}
+
+static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
+ struct device_node *np)
+{
+ const struct nand_sdr_timings *timings;
+ 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);
+
+ return sunxi_nand_chip_set_timings(chip, timings);
+}
+
+static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
+ struct device_node *np)
+{
+ const struct nand_sdr_timings *timings;
+ 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) {
+ tmp = ret;
+ 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;
+
+ ret = gpio_direction_input(tmp);
+ if (ret)
+ return ret;
+ } else {
+ chip->sels[i].rb.type = RB_NONE;
+ }
+ }
+ }
+
+ timings = onfi_async_timing_mode_to_sdr_timings(0);
+ if (IS_ERR(timings))
+ return PTR_ERR(timings);
+
+ ret = sunxi_nand_chip_set_timings(chip, timings);
+
+ 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;
+
+ ret = sunxi_nand_chip_init_timings(chip, np);
+ 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
* [PATCH v2 0/6] setting the table for integration of cpuidle with the scheduler
From: Nicolas Pitre @ 2014-01-30 13:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140130092835.GL11314@laptop.programming.kicks-ass.net>
On Thu, 30 Jan 2014, Peter Zijlstra wrote:
> On Wed, Jan 29, 2014 at 12:45:07PM -0500, Nicolas Pitre wrote:
> > As everyone should know by now, we want to integrate the cpuidle
> > governor with the scheduler for a more efficient idling of CPUs.
> > In order to help the transition, this small patch series moves the
> > existing interaction with cpuidle from architecture code to generic
> > core code. The ARM, PPC, SH and X86 architectures are concerned.
> > No functional change should have occurred yet.
> >
> > @peterz: Are you willing to pick up those patches?
>
> Yeah.. no objections. Should I pick these up or will you be sending
> another round?
I think you could pick them now, taking care of picking up the amended
#1/6.
Nicolas
^ permalink raw reply
* [PATCH V3 6/8] SPEAr13xx: Fixup: Move SPEAr1340 SATA platform code to phy driver
From: Arnd Bergmann @ 2014-01-30 13:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <7b9e0a98a6873f66e519791dfba20418e2a68c5a.1391077731.git.mohit.kumar@st.com>
On Thursday 30 January 2014, Mohit Kumar wrote:
>
> diff --git a/Documentation/devicetree/bindings/phy/spear13xx-miphy.txt b/Documentation/devicetree/bindings/phy/spear13xx-miphy.txt
> new file mode 100644
> index 0000000..208b37d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/spear13xx-miphy.txt
> @@ -0,0 +1,8 @@
> +Required properties:
> +- compatible : should be "st,spear1340-sata-pcie-phy".
Just for confirmation: This phy is by design only capable of driving
sata or pcie, but nothing else if reused in a different SoC, right?
If the phy is actually more generic than that, I'd suggest changing
the name, otherwise it's ok.
> +- reg : offset and length of the PHY register set.
> +- misc: phandle for the syscon node to access misc registers
> +- #phy-cells : from the generic PHY bindings, must be 2.
> + - 1st arg: phandle to the phy node.
> + - 2nd arg: 0 if phy (in 1st arg) is to be used for sata else 1.
> + - 3rd arg: Instance id of the phy (in 1st arg).
I would count "arg" differently: There are three cells, and the first
cell is the phandle, while the second and third cells contain the first
and second argument.
The third cell seems redundant, more on that below.
> + ahci0: ahci at b1000000 {
> compatible = "snps,spear-ahci";
> reg = <0xb1000000 0x10000>;
> interrupts = <0 68 0x4>;
> + phys = <&miphy0 0 0>;
> + phy-names = "ahci-phy";
> status = "disabled";
> };
>
> - ahci at b1800000 {
> + ahci1: ahci at b1800000 {
> compatible = "snps,spear-ahci";
> reg = <0xb1800000 0x10000>;
> interrupts = <0 69 0x4>;
> + phys = <&miphy1 0 1>;
> + phy-names = "ahci-phy";
> status = "disabled";
> };
>
> - ahci at b4000000 {
> + ahci2: ahci at b4000000 {
> compatible = "snps,spear-ahci";
> reg = <0xb4000000 0x10000>;
> interrupts = <0 70 0x4>;
> + phys = <&miphy2 0 2>;
> + phy-names = "ahci-phy";
> status = "disabled";
> };
In each case, the number of the phy 'miphyX' is identical to the
third cell, and I suspect this is by design. In the driver, the
'id' field is set in the xlate function, but I could not find any
place where it actually gets used, so unless you know that it's
needed, I'd suggest simply removing it.
Even if you need it, it may be better to have the instance encoded
in the phy node itself, since it's a property of the phy hardware
(e.g. if you have to pass the number into a generic register that
is global to all phys.
Alternatively, you could have a different representation, where you
have a single DT device node representing all three PHYs, with
"reg = <0xeb800000 0xc000>;" In that case, all sata devices would
point to the same phy node and pass the instance id so the phy
driver can operated the correct register set.
> +static int spear1340_sata_miphy_init(struct spear13xx_phy_priv *phypriv)
> +{
> + regmap_update_bits(phypriv->misc, SPEAR1340_PCIE_SATA_CFG,
> + SPEAR1340_PCIE_SATA_CFG_MASK, SPEAR1340_SATA_CFG_VAL);
> + regmap_update_bits(phypriv->misc, SPEAR1340_PCIE_MIPHY_CFG,
> + SPEAR1340_PCIE_MIPHY_CFG_MASK,
> + SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK);
> + /* Switch on sata power domain */
> + regmap_update_bits(phypriv->misc, SPEAR1340_PCM_CFG,
> + SPEAR1340_PCM_CFG_SATA_POWER_EN,
> + SPEAR1340_PCM_CFG_SATA_POWER_EN);
> + msleep(20);
> + /* Disable PCIE SATA Controller reset */
> + regmap_update_bits(phypriv->misc, SPEAR1340_PERIP1_SW_RST,
> + SPEAR1340_PERIP1_SW_RST_SATA, 0);
> + msleep(20);
> +
> + return 0;
> +}
I guess some of the parts above can eventually get moved into other
drivers (reset controller, power domains) that get called directly
by the SATA driver (e.g. though reset_device()). Since that won't
impact the PHY binding, it seems fine to leave it here for now.
Arnd
^ permalink raw reply
* [PATCH v4 2/5] arm: add new asm macro update_sctlr
From: Leif Lindholm @ 2014-01-30 13:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391029124.2488.50.camel@deneb.redhat.com>
On Wed, Jan 29, 2014 at 03:58:44PM -0500, Mark Salter wrote:
> > (i.e. conditionalise on whether an optional parameter was provided),
> > so my attempt of refactoring actually ends up using an additional
> > register:
> >
>
> Register parameters are just strings, so how about this:
>
> .macro foo bar=, baz=
> .ifnc \bar,
> mov \bar,#0
> .endif
> .ifnc \baz,
> mov \baz,#1
> .endif
> .endm
>
> foo x0
> foo
> foo x1, x2
> foo ,x3
>
> Results in:
>
> 0000000000000000 <.text>:
> 0: d2800000 mov x0, #0x0 // #0
> 4: d2800001 mov x1, #0x0 // #0
> 8: d2800022 mov x2, #0x1 // #1
> c: d2800023 mov x3, #0x1 // #1
Oh, that's neat - thanks!
Well, given that, I can think of two less horrible options:
1)
.macro update_sctlr, tmp:req, set=, clear=
mrc p15, 0, \tmp, c1, c0, 0
.ifnc \set,
orr \tmp, \set
.endif
.ifnc \clear,
mvn \clear, \clear
and \tmp, \tmp, \clear
.endif
mcr p15, 0, \tmp, c1, c0, 0
.endm
With the two call sites in uefi_phys.S as:
ldr r5, =(CR_M)
update_sctlr r12, , r5
and
ldr r4, =(CR_I | CR_C | CR_M)
update_sctlr r12, r4
Which disassembles as:
2c: e3a05001 mov r5, #1
30: ee11cf10 mrc 15, 0, ip, cr1, cr0, {0}
34: e1e05005 mvn r5, r5
38: e00cc005 and ip, ip, r5
3c: ee01cf10 mcr 15, 0, ip, cr1, cr0, {0}
and
48: e59f4034 ldr r4, [pc, #52] ; 84 <tmpstack+0x4>
4c: ee11cf10 mrc 15, 0, ip, cr1, cr0, {0}
50: e18cc004 orr ip, ip, r4
54: ee01cf10 mcr 15, 0, ip, cr1, cr0, {0}
2)
.macro update_sctlr, tmp:req, tmp2:req, set=, clear=
mrc p15, 0, \tmp, c1, c0, 0
.ifnc \set,
ldr \tmp2, =\set
orr \tmp, \tmp, \tmp2
.endif
.ifnc \clear,
ldr \tmp2, =\clear
mvn \tmp2, \tmp2
and \tmp, \tmp, \tmp2
.endif
mcr p15, 0, \tmp, c1, c0, 0
.endm
With the two call sites in uefi_phys.S as:
update_sctlr r4, r5, , (CR_M)
and
update_sctlr r4, r5, (CR_I | CR_C | CR_M)
Which disassembles as:
2c: ee114f10 mrc 15, 0, r4, cr1, cr0, {0}
30: e3a05001 mov r5, #1
34: e1e05005 mvn r5, r5
38: e0044005 and r4, r4, r5
3c: ee014f10 mcr 15, 0, r4, cr1, cr0, {0}
and
48: ee114f10 mrc 15, 0, r4, cr1, cr0, {0}
4c: e59f5030 ldr r5, [pc, #48] ; 84 <tmpstack+0x4>
50: e1844005 orr r4, r4, r5
54: ee014f10 mcr 15, 0, r4, cr1, cr0, {0}
The benefit of 2) is a cleaner call site, and one fewer register
used if setting and clearing simultaneously.
The benefit of 1) is that the macro could then easily be used with
the crval mask in mm/proc*.S
So, Will, which one do you want?
/
Leif
^ permalink raw reply
* [PATCH v2 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver
From: Greg KH @ 2014-01-30 13:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52E9E8B0.2020000@ti.com>
On Thu, Jan 30, 2014 at 11:22:48AM +0530, Satish Patel wrote:
>
> On 1/20/2014 10:03 AM, Satish Patel wrote:
> > Changes from v1:
> > * RFC(v1) comments are fixed
> >
> > ** removed "gpio_to_irq" as GPIO controller process cell from DT and
> > give it to DT node
> > ** comments on documentation
> > ** few other comments on null checks are resolved
> >
> > * BWT timing configuration is added to ti-usim driver
> >
> > v1 cover letter link#
> > https://lkml.org/lkml/2014/1/6/250
> >
> > Satish Patel (5):
> > sc_phy:SmartCard(SC) PHY interface to SC controller
> > misc: tda8026: Add NXP TDA8026 PHY driver
> > char: ti-usim: Add driver for USIM module on AM43xx
> > ARM: dts: AM43xx: DT entries added for ti-usim
> > ARM: dts: AM43xx-epos-evm: DT entries for ti-usim and phy
> >
> > Documentation/devicetree/bindings/misc/tda8026.txt | 19 +
> > .../devicetree/bindings/ti-usim/ti-usim.txt | 31 +
> > Documentation/sc_phy.txt | 171 ++
> > arch/arm/boot/dts/am4372.dtsi | 10 +
> > arch/arm/boot/dts/am43x-epos-evm.dts | 43 +
> > drivers/char/Kconfig | 7 +
> > drivers/char/Makefile | 1 +
> > drivers/char/ti-usim-hw.h | 863 +++++++++
> > drivers/char/ti-usim.c | 1859 ++++++++++++++++++++
> > drivers/misc/Kconfig | 7 +
> > drivers/misc/Makefile | 1 +
> > drivers/misc/tda8026.c | 1255 +++++++++++++
> > include/linux/sc_phy.h | 132 ++
> > include/linux/ti-usim.h | 98 +
> > 14 files changed, 4497 insertions(+), 0 deletions(-)
> > create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt
> > create mode 100644 Documentation/devicetree/bindings/ti-usim/ti-usim.txt
> > create mode 100644 Documentation/sc_phy.txt
> > create mode 100644 drivers/char/ti-usim-hw.h
> > create mode 100644 drivers/char/ti-usim.c
> > create mode 100644 drivers/misc/tda8026.c
> > create mode 100644 include/linux/sc_phy.h
> > create mode 100644 include/linux/ti-usim.h
> Any comments on this patch series ?
>
> If not,
> Can you accept these patches for next merge window
It's the middle of this merge window, and I can't accept any patches
until after 3.14-rc1 is out, at which point I'll start to work on my
patch backlog.
thanks,
greg k-h
^ permalink raw reply
* [PATCH V3 3/8] SPEAr13xx: defconfig: Update
From: Arnd Bergmann @ 2014-01-30 13:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <77553346b18c3978b12329161a85dba7d50242ca.1391077731.git.mohit.kumar@st.com>
On Thursday 30 January 2014, Mohit Kumar wrote:
> Enable EABI, OEABI, VFP and NFS configs in default configuration file for
> SPEAr13xx.
Are you sure about OABI_COMPAT? That seems unusual.
Also, please add all the options you need to multi_v7_defconfig
and ensure that this configuration works with your hardware as well.
Arnd
^ permalink raw reply
* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
From: Thomas Abraham @ 2014-01-30 12:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAPtuhTj2ZOb+5LDbqghuOhQZfVy8i1xuWotoZ6ocbJFgMxnSMQ@mail.gmail.com>
Hi Mike,
On Wed, Jan 29, 2014 at 12:17 AM, Mike Turquette <mturquette@linaro.org> wrote:
> On Mon, Jan 27, 2014 at 9:30 PM, Thomas Abraham <ta.omasab@gmail.com> wrote:
>> Hi Mike,
>>
>> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> wrote:
>>> Quoting Thomas Abraham (2014-01-18 04:10:51)
>>>> From: Thomas Abraham <thomas.ab@samsung.com>
>>>>
>>>> On some platforms such as the Samsung Exynos, changing the frequency
>>>> of the CPU clock requires changing the frequency of the PLL that is
>>>> supplying the CPU clock. To change the frequency of the PLL, the CPU
>>>> clock is temporarily reparented to another parent clock.
>>>>
>>>> The clock frequency of this temporary parent clock could be much higher
>>>> than the clock frequency of the PLL at the time of reparenting. Due
>>>> to the temporary increase in the CPU clock speed, the CPU (and any other
>>>> components in the CPU clock domain such as dividers, mux, etc.) have to
>>>> to be operated at a higher voltage level, called the safe voltage level.
>>>> This patch adds optional support to temporarily switch to a safe voltage
>>>> level during CPU frequency transitions.
>>>>
>>>> Cc: Shawn Guo <shawn.guo@linaro.org>
>>>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>>>
>>> I'm not a fan of this change. This corner case should be abstracted away
>>> somehow. I had talked to Chander Kayshap previously about handling
>>> voltage changes in clock notifier callbacks, which then renders any
>>> voltage change as a trivial part of the clock rate transition. That
>>> means that this "safe voltage" thing could be handled automagically
>>> without any additional code in the CPUfreq driver.
>>>
>>> There are two nice ways to do this with the clock framework. First is
>>> explicit re-parenting with voltage scaling done in the clock rate-change
>>> notifiers:
>>>
>>> clk_set_parent(cpu_clk, temp_parent);
>>> /* implicit voltage scaling to "safe voltage" happens above */
>>> clk_set_rate(pll, some_rate);
>>> clk_set_parent(cpu_clk, pll);
>>> /* implicit voltage scaling to nominal OPP voltage happens above */
>>>
>>> The above sequence would require a separate exnyos CPUfreq driver, due
>>> to the added clk_set_parent logic.
>>>
>>> The second way to do this is to abstract the clk re-muxing logic out
>>> into the clk driver, which would allow cpufreq-cpu0 to be used for the
>>> exynos chips.
>>
>> This is the approach this patch series takes (patch 2/7). The clock
>> re-muxing logic is handled by a clock driver code. The difference from
>> what you suggested is that the safe voltage (that may be optionally)
>> required before doing the re-muxing is handled here in cpufreq-cpu0
>> driver.
>
> Right, I understand the approach taken in this series and I'm not sure
> it is the right one. Why does the clock driver handle the remuxing if
> it is a functional dependency of the ARM core?
The output of the PLL is the input to a tree of clock nodes. One of
the outputs from this tree is the clock to ARM. And the other outputs
do not serve as parents to any other clocks in the system but are used
internally in the bus interconnect. In addition to that, there are
clock speed restrictions for the clock outputs from this tree with
respect to speeds of other clocks in this clock tree.
Hence, this entire clock tree has been purged into a single composite
clock which includes mux and dividers. So the clock tree now looks
like PLL Output -> Custom Composite Clock -> ARM clock output.
But there is a problem when changing the ARM clock speed which in turn
causes change in PLL clock speed. When PLL clock speed has to be
changed, the PLL has to be first turned off. Which means the clock to
ARM core is cut-off. To avoid that, the Custom Composite Clock now has
to get its clock from another source until the PLL is ready to operate
again. So this composite clock does an automatic re-parenting (the mux
is within is composite clock) because it knows that it is its
responsibility to ensure clock ARM all the time.
> As far as I can tell
> the remux does not happen because it is necessary to generate the
> required clock rate, but because we don't want to run the ARM core out
> of spec for a short time while the PLL relocks. Assuming I have that
> part of it right, I prefer for the parent mux operation to be a part
> of the CPUfreq driver's .target callback instead of hidden away in the
> clock driver.
The re-parenting is mostly done to keep the ARM CPU clocked while the
PLL is stopped, reprogrammed and restarted. One of the side effects of
that is, the clock speed of the temporary parent could be higher then
what is allowed due to the ARM voltage at the time of re-parenting.
That is the reason to use the safe voltage.
>
> A common pattern I'm seeing for the last 18 months is code
> consolidation for the sake of code consolidation and it is not always
> a good thing. Having hardware-specific machine drivers under
> drivers/cpufreq/ is the right way to go, and we should only
> consolidate a driver to cpufreq-cpu0 if it makes sense.
Okay.I agree. And I did feel that adding the optional "safe voltage"
feature in cpufreq-cpu0 would help Exynos platforms reuse this driver.
And adding this feature in cpufreq-cpu did not feel like some
orthogonal approach but a logical extension.
>
>>
>> The safe voltage setup can be done in the notifier as you suggested.
>> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
>> this feature if required. Also, if done here, the regulator handling
>> is localized in this driver which otherwise would need to be handled
>> in two places, cpufreq-cpu0 driver and the clock notifier.
>
> The notifiers are reusable across other platforms. And the notifier
> can be entirely set up within the cpufreq driver. Code location is not
> a problem. See this RFC series:
> https://lkml.org/lkml/2013/7/7/110
Okay.
>
>>
>> So I tend to prefer the approach in this patch but I am willing to
>> consider any suggestions. Shawn, it would be helpful if you could let
>> us know your thoughts on this. I am almost done with testing the v3 of
>> this series and want to post it so if there are any objections to the
>> changes in this patch, please let me know.
>
> Well I wonder if the whole approach could be more generalized. The DT
> bindings for CPU frequencies could be used by any platform instead of
> being Exynos-specific. We could construct a binding which captures an
> arbitrary clock sub-tree snapshot. By that I mean a DT binding in
> which any number of clocks and their parents and rates could be
> specified in a table. Separately we could have a binding that links a
> given clock at a given rate to some specified regulator and voltage.
> So in this way the bindings are re-usable.
>
> These DT ideas should be considered separately from the CPUfreq notes
> outlined above, and I will respond to patch #3 in this series once I
> have a chance.
Okay. Thanks Mike for your comments. And sorry for the delay in my reply.
Regards,
Thomas.
>
> Thanks,
> Mike
>
>>
>> Thanks,
>> Thomas.
>>
>>>
>>> I'm more a fan of explicitly listing the Exact Steps for the cpu opp
>>> transition in a separate exynos-specific CPUfreq driver, but that's
>>> probably an unpopular view.
>>>
>>> Regards,
>>> Mike
>>>
>>>> ---
>>>> .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt | 7 ++++
>>>> drivers/cpufreq/cpufreq-cpu0.c | 37 +++++++++++++++++--
>>>> 2 files changed, 40 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>>>> index f055515..37453ab 100644
>>>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>>>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>>>> @@ -19,6 +19,12 @@ Optional properties:
>>>> - cooling-min-level:
>>>> - cooling-max-level:
>>>> Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
>>>> +- safe-opp: Certain platforms require that during a opp transition,
>>>> + a system should not go below a particular opp level. For such systems,
>>>> + this property specifies the minimum opp to be maintained during the
>>>> + opp transitions. The safe-opp value is a tuple with first element
>>>> + representing the safe frequency and the second element representing the
>>>> + safe voltage.
>>>>
>>>> Examples:
>>>>
>>>> @@ -36,6 +42,7 @@ cpus {
>>>> 396000 950000
>>>> 198000 850000
>>>> >;
>>>> + safe-opp = <396000 950000>
>>>> clock-latency = <61036>; /* two CLK32 periods */
>>>> #cooling-cells = <2>;
>>>> cooling-min-level = <0>;
>>>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
>>>> index 0c12ffc..075d3d1 100644
>>>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>>>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>>>> @@ -27,6 +27,8 @@
>>>>
>>>> static unsigned int transition_latency;
>>>> static unsigned int voltage_tolerance; /* in percentage */
>>>> +static unsigned long safe_frequency;
>>>> +static unsigned long safe_voltage;
>>>>
>>>> static struct device *cpu_dev;
>>>> static struct clk *cpu_clk;
>>>> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>>> volt_old = regulator_get_voltage(cpu_reg);
>>>> }
>>>>
>>>> - pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
>>>> + pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>>>> old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>>>> new_freq / 1000, volt ? volt / 1000 : -1);
>>>>
>>>> /* scaling up? scale voltage before frequency */
>>>> - if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
>>>> + if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
>>>> + new_freq >= safe_frequency) {
>>>> ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>>> if (ret) {
>>>> pr_err("failed to scale voltage up: %d\n", ret);
>>>> return ret;
>>>> }
>>>> + } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
>>>> + /*
>>>> + * the scaled up voltage level for the new_freq is lower
>>>> + * than the safe voltage level. so set safe_voltage
>>>> + * as the intermediate voltage level and revert it
>>>> + * back after the frequency has been changed.
>>>> + */
>>>> + ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
>>>> + if (ret) {
>>>> + pr_err("failed to set safe voltage: %d\n", ret);
>>>> + return ret;
>>>> + }
>>>> }
>>>>
>>>> ret = clk_set_rate(cpu_clk, freq_exact);
>>>> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>>> }
>>>>
>>>> /* scaling down? scale voltage after frequency */
>>>> - if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
>>>> + if (!IS_ERR(cpu_reg) &&
>>>> + (new_freq < old_freq || new_freq < safe_frequency)) {
>>>> ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>>> if (ret) {
>>>> pr_err("failed to scale voltage down: %d\n", ret);
>>>> @@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
>>>>
>>>> static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>>> {
>>>> + const struct property *prop;
>>>> + struct dev_pm_opp *opp;
>>>> struct device_node *np;
>>>> int ret;
>>>>
>>>> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>>> goto out_put_node;
>>>> }
>>>>
>>>> + prop = of_find_property(np, "safe-opp", NULL);
>>>> + if (prop) {
>>>> + if (prop->value && (prop->length / sizeof(u32)) == 2) {
>>>> + const __be32 *val;
>>>> + val = prop->value;
>>>> + safe_frequency = be32_to_cpup(val++);
>>>> + safe_voltage = be32_to_cpup(val);
>>>> + } else {
>>>> + pr_err("invalid safe-opp level specified\n");
>>>> + }
>>>> + }
>>>> +
>>>> of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
>>>>
>>>> if (of_property_read_u32(np, "clock-latency", &transition_latency))
>>>> transition_latency = CPUFREQ_ETERNAL;
>>>>
>>>> if (!IS_ERR(cpu_reg)) {
>>>> - struct dev_pm_opp *opp;
>>>> unsigned long min_uV, max_uV;
>>>> int i;
>>>>
>>>> --
>>>> 1.6.6.rc2
>>>>
^ permalink raw reply
* [RFC] dtc: add ability to make nodes conditional on them being referenced
From: Lothar Waßmann @ 2014-01-30 12:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1578575.rVWgTPdq1W@phil>
Hi,
Heiko St?bner wrote:
> From: Heiko Stuebner <heiko.stuebner@bqreaders.com>
>
> On i.MX, which carries a lot of pin-groups of which most are unused on
> individual boards, they noticed that this plehora of nodes also results
> in the runtime-lookup-performance also degrading [0].
>
> A i.MX-specific solution defining the pingroups in the board files but
> using macros to reference the pingroup-data was not well received
>
> This patch is trying to solve this issue in a more general way, by
> adding the ability to mark nodes as needing to be referenced somewhere
> in the tree.
>
> To mark a node a needing to be referenced it must be prefixed with
> /delete-unreferenced/. This makes dtc check the nodes reference-status
> when creating the flattened tree, dropping it if unreferenced.
>
> For example, the i.MX6SL pingroup
>
> /delete-uneferenced/ pinctrl_ecspi1_1: ecspi1grp-1 {
^^
s/unef/unref/
not really important here, but bad for copy/pasters
Lothar Wa?mann
--
___________________________________________________________
Ka-Ro electronics GmbH | Pascalstra?e 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Gesch?ftsf?hrer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________
^ permalink raw reply
* [RFC] dtc: add ability to make nodes conditional on them being referenced
From: Heiko Stübner @ 2014-01-30 12:25 UTC (permalink / raw)
To: linux-arm-kernel
From: Heiko Stuebner <heiko.stuebner@bqreaders.com>
On i.MX, which carries a lot of pin-groups of which most are unused on
individual boards, they noticed that this plehora of nodes also results
in the runtime-lookup-performance also degrading [0].
A i.MX-specific solution defining the pingroups in the board files but
using macros to reference the pingroup-data was not well received
This patch is trying to solve this issue in a more general way, by
adding the ability to mark nodes as needing to be referenced somewhere
in the tree.
To mark a node a needing to be referenced it must be prefixed with
/delete-unreferenced/. This makes dtc check the nodes reference-status
when creating the flattened tree, dropping it if unreferenced.
For example, the i.MX6SL pingroup
/delete-uneferenced/ pinctrl_ecspi1_1: ecspi1grp-1 {
fsl,pins = <
MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1
MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x100b1
MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x100b1
>;
};
would only be included in the dtb if it got referenced somewhere
as pingroup via
node {
pinctrl-0 <&pinctrl_ecscpi1_1>;
};
[0] http://thread.gmane.org/gmane.linux.ports.arm.kernel/275912/
Signed-off-by: Heiko Stuebner <heiko.stuebner@bqreaders.com>
---
This is just the idea I had in [1] explored a bit more. I'm definitely
not sure if this is a valid approach to the problem.
Also this is my first venture into dtc as well as flex and bison :-) .
[1] http://www.spinics.net/lists/arm-kernel/msg303731.html
scripts/dtc/checks.c | 2 ++
scripts/dtc/dtc-lexer.l | 7 +++++++
scripts/dtc/dtc-parser.y | 5 +++++
scripts/dtc/dtc.h | 4 ++++
scripts/dtc/flattree.c | 3 +++
scripts/dtc/livetree.c | 14 ++++++++++++++
6 files changed, 35 insertions(+)
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
index ee96a25..747ada8 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -472,6 +472,8 @@ static void fixup_phandle_references(struct check *c, struct node *dt,
phandle = get_node_phandle(dt, refnode);
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
+
+ reference_node(refnode);
}
}
ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
index 3b41bfc..3b18e97 100644
--- a/scripts/dtc/dtc-lexer.l
+++ b/scripts/dtc/dtc-lexer.l
@@ -138,6 +138,13 @@ static int pop_input_file(void);
return DT_DEL_NODE;
}
+<*>"/delete-unreferenced/" {
+ DPRINT("Keyword: /delete-unreferenced/\n");
+ DPRINT("<PROPNODENAME>\n");
+ BEGIN(PROPNODENAME);
+ return DT_DEL_UNREFERENCED;
+ }
+
<*>{LABEL}: {
DPRINT("Label: %s\n", yytext);
yylval.labelref = xstrdup(yytext);
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
index f412460..ae9108b 100644
--- a/scripts/dtc/dtc-parser.y
+++ b/scripts/dtc/dtc-parser.y
@@ -64,6 +64,7 @@ static unsigned char eval_char_literal(const char *s);
%token DT_BITS
%token DT_DEL_PROP
%token DT_DEL_NODE
+%token DT_DEL_UNREFERENCED
%token <propnodename> DT_PROPNODENAME
%token <literal> DT_LITERAL
%token <literal> DT_CHAR_LITERAL
@@ -461,6 +462,10 @@ subnode:
{
$$ = name_node(build_node_delete(), $2);
}
+ | DT_DEL_UNREFERENCED subnode
+ {
+ $$ = check_node_referenced($2);
+ }
| DT_LABEL subnode
{
add_label(&$2->labels, $1);
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 3e42a07..c10c440 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -159,6 +159,8 @@ struct node {
int addr_cells, size_cells;
struct label *labels;
+
+ int needs_reference, is_referenced;
};
#define for_each_label_withdel(l0, l) \
@@ -193,6 +195,8 @@ struct property *reverse_properties(struct property *first);
struct node *build_node(struct property *proplist, struct node *children);
struct node *build_node_delete(void);
struct node *name_node(struct node *node, char *name);
+struct node *check_node_referenced(struct node *node);
+struct node *reference_node(struct node *node);
struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node);
diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
index 665dad7..a327592 100644
--- a/scripts/dtc/flattree.c
+++ b/scripts/dtc/flattree.c
@@ -266,6 +266,9 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
if (tree->deleted)
return;
+ if (tree->needs_reference && !tree->is_referenced)
+ return;
+
emit->beginnode(etarget, tree->labels);
if (vi->flags & FTF_FULLPATH)
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c
index b61465f..98bb33d 100644
--- a/scripts/dtc/livetree.c
+++ b/scripts/dtc/livetree.c
@@ -134,6 +134,20 @@ struct node *name_node(struct node *node, char *name)
return node;
}
+struct node *check_node_referenced(struct node *node)
+{
+ node->needs_reference = 1;
+
+ return node;
+}
+
+struct node *reference_node(struct node *node)
+{
+ node->is_referenced = 1;
+
+ return node;
+}
+
struct node *merge_nodes(struct node *old_node, struct node *new_node)
{
struct property *new_prop, *old_prop;
--
1.7.10.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox