* [PATCH v2 1/2] misc: atmel-ssc: register as sound DAI if #sound-dai-cells is present
From: Nicolas Ferre @ 2016-12-07 9:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481052157-23400-2-git-send-email-peda@axentia.se>
Le 06/12/2016 ? 20:22, Peter Rosin a ?crit :
> The SSC is currently not usable with the ASoC simple-audio-card, as
> every SSC audio user has to build a platform driver that may do as
> little as calling atmel_ssc_set_audio/atmel_ssc_put_audio (which
> allocates the SSC and registers a DAI with the ASoC subsystem).
>
> So, have that happen automatically, if the #sound-dai-cells property
> is present in devicetree, which it has to be anyway for simple audio
> card to work.
>
> Acked-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Peter Rosin <peda@axentia.se>
Sounds okay: thanks Peter.
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
I don't think my tag is needed for second patch but you can add it if
you wish.
Regards,
> ---
> .../devicetree/bindings/misc/atmel-ssc.txt | 2 +
> drivers/misc/atmel-ssc.c | 50 ++++++++++++++++++++++
> include/linux/atmel-ssc.h | 1 +
> 3 files changed, 53 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
> index efc98ea1f23d..f8629bb73945 100644
> --- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt
> +++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
> @@ -24,6 +24,8 @@ Optional properties:
> this parameter to choose where the clock from.
> - By default the clock is from TK pin, if the clock from RK pin, this
> property is needed.
> + - #sound-dai-cells: Should contain <0>.
> + - This property makes the SSC into an automatically registered DAI.
>
> Examples:
> - PDC transfer:
> diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
> index 0516ecda54d3..b2a0340f277e 100644
> --- a/drivers/misc/atmel-ssc.c
> +++ b/drivers/misc/atmel-ssc.c
> @@ -20,6 +20,8 @@
>
> #include <linux/of.h>
>
> +#include "../../sound/soc/atmel/atmel_ssc_dai.h"
> +
> /* Serialize access to ssc_list and user count */
> static DEFINE_SPINLOCK(user_lock);
> static LIST_HEAD(ssc_list);
> @@ -145,6 +147,49 @@ static inline const struct atmel_ssc_platform_data * __init
> platform_get_device_id(pdev)->driver_data;
> }
>
> +#ifdef CONFIG_SND_ATMEL_SOC_SSC
> +static int ssc_sound_dai_probe(struct ssc_device *ssc)
> +{
> + struct device_node *np = ssc->pdev->dev.of_node;
> + int ret;
> + int id;
> +
> + ssc->sound_dai = false;
> +
> + if (!of_property_read_bool(np, "#sound-dai-cells"))
> + return 0;
> +
> + id = of_alias_get_id(np, "ssc");
> + if (id < 0)
> + return id;
> +
> + ret = atmel_ssc_set_audio(id);
> + ssc->sound_dai = !ret;
> +
> + return ret;
> +}
> +
> +static void ssc_sound_dai_remove(struct ssc_device *ssc)
> +{
> + if (!ssc->sound_dai)
> + return;
> +
> + atmel_ssc_put_audio(of_alias_get_id(ssc->pdev->dev.of_node, "ssc"));
> +}
> +#else
> +static inline int ssc_sound_dai_probe(struct ssc_device *ssc)
> +{
> + if (of_property_read_bool(ssc->pdev->dev.of_node, "#sound-dai-cells"))
> + return -ENOTSUPP;
> +
> + return 0;
> +}
> +
> +static inline void ssc_sound_dai_remove(struct ssc_device *ssc)
> +{
> +}
> +#endif
> +
> static int ssc_probe(struct platform_device *pdev)
> {
> struct resource *regs;
> @@ -204,6 +249,9 @@ static int ssc_probe(struct platform_device *pdev)
> dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n",
> ssc->regs, ssc->irq);
>
> + if (ssc_sound_dai_probe(ssc))
> + dev_err(&pdev->dev, "failed to auto-setup ssc for audio\n");
> +
> return 0;
> }
>
> @@ -211,6 +259,8 @@ static int ssc_remove(struct platform_device *pdev)
> {
> struct ssc_device *ssc = platform_get_drvdata(pdev);
>
> + ssc_sound_dai_remove(ssc);
> +
> spin_lock(&user_lock);
> list_del(&ssc->list);
> spin_unlock(&user_lock);
> diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
> index 7c0f6549898b..fdb545101ede 100644
> --- a/include/linux/atmel-ssc.h
> +++ b/include/linux/atmel-ssc.h
> @@ -20,6 +20,7 @@ struct ssc_device {
> int user;
> int irq;
> bool clk_from_rk_pin;
> + bool sound_dai;
> };
>
> struct ssc_device * __must_check ssc_request(unsigned int ssc_num);
>
--
Nicolas Ferre
^ permalink raw reply
* [PATCH 04/16] drivers/fsi: Add fsi master definition
From: Greg KH @ 2016-12-07 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481076574-54711-1-git-send-email-christopher.lee.bostic@gmail.com>
On Tue, Dec 06, 2016 at 08:09:30PM -0600, Chris Bostic wrote:
> From: Jeremy Kerr <jk@ozlabs.org>
>
> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
> Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
> ---
> drivers/fsi/fsi-core.c | 20 ++++++++++++++++++++
> drivers/fsi/fsi-master.h | 37 +++++++++++++++++++++++++++++++++++++
> 2 files changed, 57 insertions(+)
> create mode 100644 drivers/fsi/fsi-master.h
>
> diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
> index 3d55bd5..ce9428d 100644
> --- a/drivers/fsi/fsi-core.c
> +++ b/drivers/fsi/fsi-core.c
> @@ -17,6 +17,26 @@
> #include <linux/fsi.h>
> #include <linux/module.h>
>
> +#include "fsi-master.h"
> +
> +static atomic_t master_idx = ATOMIC_INIT(-1);
You don't really want/need an atomic variable, please use the simple ida
interface instead.
thanks,
greg k-h
^ permalink raw reply
* [PATCH 0/2] Hibernate fixes for 'Fix memmap to be initialized for the entire section'
From: Robert Richter @ 2016-12-07 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161206173810.GU2498@arm.com>
On 06.12.16 17:38:11, Will Deacon wrote:
> On Mon, Dec 05, 2016 at 03:42:14PM +0000, Ard Biesheuvel wrote:
> > On 2 December 2016 at 14:49, James Morse <james.morse@arm.com> wrote:
> > > Patch "arm64: mm: Fix memmap to be initialized for the entire section"
> > > changes pfn_valid() in a way that breaks hibernate. These patches fix
> > > hibernate, and provided struct page's are allocated for nomap pages,
> > > can be applied before [0].
> > >
> > > Hibernate core code belives 'valid' to mean "I can access this". It
> > > uses pfn_valid() to test the page if the page is 'valid'.
> > >
> > > pfn_valid() needs to be changed so that all struct pages in a numa
> > > node have the same node-id. Currently 'nomap' pages are skipped, and
> > > retain their pre-numa node-ids, which leads to a later BUG_ON().
> > >
> > > These patches make hibernate's savable_page() take its escape route
> > > via 'if (PageReserved(page) && pfn_is_nosave(pfn))'.
> > >
> >
> > This makes me feel slightly uneasy. Robert makes a convincing point,
> > but I wonder if we can expect more fallout from the ambiguity of
> > pfn_valid(). Now we are not only forced to assign non-existing (as far
> > as the OS is concerned) pages to the correct NUMA node, we also need
> > to set certain page flags.
>
> Yes, I really don't know how to proceed here. Playing whack-a-mole with
> pfn_valid() users doesn't sounds like an improvement on the current
> situation to me.
>
> Robert -- if we leave pfn_valid() as it is, would a point-hack to
> memmap_init_zone help, or do you anticipate other problems?
I would suggest to fix the hibernation code as I commented on before
to use pfn_is_nosave() that defaults to pfn_valid() but uses memblock_
is_nomap() for arm64. Let's just fix it and see if no other issues
arise. I am trying to send a patch for this until tomorrow.
I am also going to see how early_pfn_valid() could be redirected to
use memblock_is_nomap() on arm64. That would "quick fix" the problem,
though I rather prefer to go further with the current solution.
-Robert
^ permalink raw reply
* [PATCH v5] ARM: davinci: da8xx: Fix sleeping function called from invalid context
From: Alexandre Bailon @ 2016-12-07 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <22aec236-83f0-ea2d-8657-c99f95389611@lechnology.com>
On 12/06/2016 07:56 PM, David Lechner wrote:
> On 12/06/2016 03:57 AM, Sekhar Nori wrote:
>> On Tuesday 06 December 2016 03:21 PM, Alexandre Bailon wrote:
>>> On 12/06/2016 10:33 AM, Sekhar Nori wrote:
>>>> On Monday 05 December 2016 07:43 PM, Alexandre Bailon wrote:
>>>>> Everytime the usb20 phy is enabled, there is a
>>>>> "sleeping function called from invalid context" BUG.
>>>>>
>>>>> clk_enable() from arch/arm/mach-davinci/clock.c uses
>>>>> spin_lock_irqsave()
>>>>> before to invoke the callback usb20_phy_clk_enable().
>>>>> usb20_phy_clk_enable() uses clk_get() and clk_enable_prepapre()
>>>>> which may sleep.
>>>>> Move clk_get() to da8xx_register_usb20_phy_clk() and
>>>>> replace clk_prepare_enable() by clk_enable().
>>>>>
>>>>> Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
>>>>
>>>> This will still cause the recursive locking problem reported by David.
>>>> Not sure what the point of sending this version was.
>>>>
>>>> Thanks,
>>>> Sekhar
>>>>
>>
>>> What am I supposed to do ?
>>
>> That needs to be resolved between you and David. Perhaps convert the fix
>> sent by David into a proper patch and base this patch on that. Or wait
>> for David to send it himself and let him also make the modifications
>> needed in this patch.
>>
>> David ?
>>
>> Thanks,
>> Sekhar
>>
>
> Alexandre, I was hoping that you would just squash my patch with your
> patch and take Sekhar's suggestion about a separate patch to make the
> private __clk_enable() public as davinci_clk_enable() when you re-submit.
OK.
>
> You can add "Suggested-By: David Lechner <david@lechnology.com>" to the
> commit message if you would like to give me some credit for my ideas.
That was my concern. I will do that.
Thanks,
Alexandre
^ permalink raw reply
* [PATCH 0/4] arm/versatile: no-MMU support
From: Vladimir Murzin @ 2016-12-07 9:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481090912-29835-1-git-send-email-gerg@uclinux.org>
Hi Greg,
On 07/12/16 06:08, Greg Ungerer wrote:
> Does the ARM Versatile machine have a maintainer?
> I have CC'ed this patch set to those names reported by get_maintainer.
> I had no feedback on the first posting of this series back in August.
>
> The following patches support configuring and building the versatile
> machine with a no-MMU kernel.
>
> There is only a few minor changes required. It was previously possible
> in older kernels to build for versatile with CONFIG_MMU disabled, but
> the change to devicetree lost that capability. These changes make it
> possible again.
>
> One patch is a fix for address translation (broken in older kernels too),
> two are build problems when CONFIG_MMU is disabled, and the last is the
> actuall configuration changes needed.
>
> The motivation for this is that the versatile machine is well supported
> in qemu. And this provides an excellent platform for development and
> testing no-MMU support on ARM in general. With these patches applied
> it is possible to build and run a kernel with MMU disabled on qemu.
I'm wondering if my "Allow NOMMU for MULTIPLATFORM" series [1] work for you?
[1] https://www.spinics.net/lists/arm-kernel/msg546823.html
Cheers
Vladimir
>
> Signed-off-by: Greg Ungerer <gerg@uclinux.org>
> ---
> arch/arm/Kconfig | 10 ++++++++++
> arch/arm/Kconfig.debug | 3 ++-
> arch/arm/include/asm/mach/map.h | 1 +
> arch/arm/mach-versatile/Kconfig | 3 ++-
> arch/arm/mach-versatile/Makefile.boot | 3 +++
> arch/arm/mach-versatile/versatile_dt.c | 4 ++++
> 6 files changed, 22 insertions(+), 2 deletions(-)
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply
* [PATCH 11/16] drivers/fsi: Add device read/write/peek functions
From: Greg KH @ 2016-12-07 9:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481076574-54711-4-git-send-email-christopher.lee.bostic@gmail.com>
On Tue, Dec 06, 2016 at 08:09:33PM -0600, Chris Bostic wrote:
> diff --git a/include/linux/fsi.h b/include/linux/fsi.h
> index efa55ba..66bce48 100644
> --- a/include/linux/fsi.h
> +++ b/include/linux/fsi.h
> @@ -27,6 +27,12 @@ struct fsi_device {
> uint32_t size;
> };
>
> +extern int fsi_device_read(struct fsi_device *dev, uint32_t addr,
> + void *val, size_t size);
> +extern int fsi_device_write(struct fsi_device *dev, uint32_t addr,
> + const void *val, size_t size);
> +extern int fsi_device_peek(struct fsi_device *dev, void *val);
> +
> struct fsi_device_id {
> u8 engine_type;
> u8 version;
> @@ -40,7 +46,6 @@ struct fsi_device_id {
> #define FSI_DEVICE_VERSIONED(t, v) \
> .engine_type = (t), .version = (v),
>
> -
> struct fsi_driver {
> struct device_driver drv;
> const struct fsi_device_id *id_table;
Strange whitespace change here :)
Not a real problem, I like the fact that you have broken this down into
very logical pieces making it much easier to review, thanks so much for
doing this.
greg k-h
^ permalink raw reply
* [PATCH 14/16] drivers/fsi: Add master unscan
From: Greg KH @ 2016-12-07 9:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481069677-53660-15-git-send-email-christopher.lee.bostic@gmail.com>
On Tue, Dec 06, 2016 at 06:14:35PM -0600, Chris Bostic wrote:
> From: Chris Bostic <cbostic@us.ibm.com>
>
> Allow a master to undo a previous scan. Should a master scan a bus
> twice it will need to ensure it doesn't double register any
> previously detected device.
>
> Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
> ---
> drivers/fsi/fsi-core.c | 36 +++++++++++++++++++++++++++++++++++-
> drivers/fsi/fsi-master.h | 2 ++
> include/linux/fsi.h | 1 +
> 3 files changed, 38 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
> index a28434b..8ccfe50 100644
> --- a/drivers/fsi/fsi-core.c
> +++ b/drivers/fsi/fsi-core.c
> @@ -41,6 +41,8 @@
> static atomic_t master_idx = ATOMIC_INIT(-1);
>
> struct fsi_slave {
> + struct list_head list_link; /* Master's list of slaves */
> + struct list_head my_engines;
> struct device dev;
> struct fsi_master *master;
> int link;
> @@ -196,6 +198,8 @@ static int fsi_slave_scan(struct fsi_slave *slave)
> uint32_t conf;
> int rc, i;
>
> + INIT_LIST_HEAD(&slave->my_engines);
> +
> /*
> * scan engines
> *
> @@ -264,7 +268,9 @@ static int fsi_slave_scan(struct fsi_slave *slave)
> if (rc) {
> dev_warn(&slave->dev, "add failed: %d\n", rc);
> put_device(&dev->dev);
> + continue;
> }
> + list_add(&dev->link, &slave->my_engines);
> }
>
> engine_addr += slots * engine_page_size;
> @@ -357,7 +363,7 @@ static int fsi_slave_init(struct fsi_master *master,
> put_device(&slave->dev);
> return rc;
> }
> -
> + list_add(&slave->list_link, &master->my_slaves);
> fsi_slave_scan(slave);
> return 0;
> }
> @@ -388,6 +394,11 @@ static int fsi_master_scan(struct fsi_master *master)
> int link, slave_id, rc;
> uint32_t smode;
>
> + if (!master->slave_list) {
> + INIT_LIST_HEAD(&master->my_slaves);
> + master->slave_list = true;
> + }
> +
> for (link = 0; link < master->n_links; link++) {
> rc = fsi_master_link_enable(master, link);
> if (rc) {
> @@ -423,9 +434,31 @@ static int fsi_master_scan(struct fsi_master *master)
> return 0;
> }
>
> +static void fsi_master_unscan(struct fsi_master *master)
> +{
> + struct fsi_slave *slave, *slave_tmp;
> + struct fsi_device *fsi_dev, *fsi_dev_tmp;
> +
> + if (!master->slave_list)
> + return;
> +
> + list_for_each_entry_safe(slave, slave_tmp, &master->my_slaves,
> + list_link) {
> + list_del(&slave->list_link);
> + list_for_each_entry_safe(fsi_dev, fsi_dev_tmp,
> + &slave->my_engines, link) {
> + list_del(&fsi_dev->link);
> + put_device(&fsi_dev->dev);
> + }
> + device_unregister(&slave->dev);
> + }
> + master->slave_list = false;
> +}
> +
> int fsi_master_register(struct fsi_master *master)
> {
> master->idx = atomic_inc_return(&master_idx);
> + master->slave_list = false;
> get_device(master->dev);
> fsi_master_scan(master);
> return 0;
> @@ -434,6 +467,7 @@ int fsi_master_register(struct fsi_master *master)
>
> void fsi_master_unregister(struct fsi_master *master)
> {
> + fsi_master_unscan(master);
> put_device(master->dev);
> }
> EXPORT_SYMBOL_GPL(fsi_master_unregister);
> diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
> index 56aad0e..454af2b 100644
> --- a/drivers/fsi/fsi-master.h
> +++ b/drivers/fsi/fsi-master.h
> @@ -20,6 +20,8 @@
> #include <linux/device.h>
>
> struct fsi_master {
> + struct list_head my_slaves;
> + bool slave_list;
> struct device *dev;
> int idx;
> int n_links;
> diff --git a/include/linux/fsi.h b/include/linux/fsi.h
> index 66bce48..924502b 100644
> --- a/include/linux/fsi.h
> +++ b/include/linux/fsi.h
> @@ -18,6 +18,7 @@
> #include <linux/device.h>
>
> struct fsi_device {
> + struct list_head link; /* for slave's list */
Can't you use the device list on the bus instead? Putting a device on
multiple lists gets tricky very quickly :(
thanks,
greg k-h
^ permalink raw reply
* [Nouveau] 4.9-rc7 nouveau fails on arm64 64k page kernel but works with 4k
From: Alexandre Courbot @ 2016-12-07 9:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKb7UvgW331K53x3wub5o+6LOqeLN5PqgiiJG6WXi+WJDVDzDg@mail.gmail.com>
On Fri, Dec 2, 2016 at 12:23 PM, Ilia Mirkin <imirkin@alum.mit.edu> wrote:
> That's right -- nouveau currently requires 4k page sizes to work. This is a
> software limitation, not a hardware one though.
Looking at the trace I wonder - is the limitation in Nouveau or in TTM?
>
>
> On Dec 1, 2016 5:13 PM, "Jeremy Linton" <jeremy.linton@arm.com> wrote:
>
> Hi,
>
> I placed a 9600GT in a softiron 3k running fedora 25, and the nouveau driver
> failed to claim the device with :
>
> [drm] Initialized
> nouveau 0000:01:00.0: NVIDIA G94 (094100a1)
> nouveau 0000:01:00.0: bios: version 62.94.0d.00.04
> nouveau: probe of 0000:01:00.0 failed with error -22
>
> Which with a little bit of debugging seems to be a failure in:
>
> [77216.692605] [<ffff000001404120>] ttm_bo_validate+0xb0/0x1e8 [ttm]
> [77216.698697] [<ffff0000014045ac>] ttm_bo_init+0x354/0x410 [ttm]
> [77216.704706] [<ffff0000019d7bd0>] nouveau_bo_new+0x1f4/0x314 [nouveau]
> [77216.711308] [<ffff0000019e4620>] nv50_display_create+0x10c/0xa1c
> [nouveau]
> [77216.718340] [<ffff0000019df898>] nouveau_display_create+0x50c/0x59c
> [nouveau]
> [77216.725632] [<ffff0000019d3e24>] nouveau_drm_load+0x22c/0x8c0 [nouveau]
> [77216.732286] [<ffff00000137a1a0>] drm_dev_register+0xc0/0xf0 [drm]
> [77216.738409] [<ffff00000137b8a4>] drm_get_pci_dev+0xbc/0x188 [drm]
> [77216.744663] [<ffff0000019d35e8>] nouveau_drm_probe+0x180/0x208 [nouveau]
> [77216.751354] [<ffff0000084c30dc>] local_pci_probe+0x50/0xb4
> [77216.756827] [<ffff0000084c3e40>] pci_device_probe+0xf8/0x148
> [77216.762474] [<ffff0000085b6a10>] driver_probe_device+0x284/0x420
> [77216.768467] [<ffff0000085b6ccc>] __driver_attach+0x120/0x124
> [77216.774115] [<ffff0000085b446c>] bus_for_each_dev+0x6c/0xac
> [77216.779673] [<ffff0000085b6204>] driver_attach+0x2c/0x34
> [77216.784972] [<ffff0000085b5cb4>] bus_add_driver+0x244/0x2b0
> [77216.790531] [<ffff0000085b78e4>] driver_register+0x68/0xfc
> [77216.796004] [<ffff0000084c29a8>] __pci_register_driver+0x60/0x6c
> [77216.802047] [<ffff00000137bcb8>] drm_pci_init+0x108/0x138 [drm]
> [77216.808146] [<ffff000001530158>] nouveau_drm_init+0x158/0x10000 [nouveau]
> [77216.814922] [<ffff0000080831a8>] do_one_initcall+0x44/0x128
> [77216.820483] [<ffff0000081cad6c>] do_init_module+0x68/0x1e0
> [77216.825957] [<ffff000008150d84>] load_module+0xfac/0x12bc
> [77216.831343] [<ffff00000815132c>] SyS_finit_module+0xe4/0xf0
> [77216.836902] [<ffff000008082b70>] el0_svc_naked+0x24/0x28
>
> By default fedora is using a 64k page kernel, switching to a mainline
> 4.9-rc7 kernel using the same configuration the same problem exists (there
> are a couple others, mentioned briefly in the defect). Changing the mainline
> kernel from 64k to 4k pages corrects the problem and a terminal display can
> be seen.
>
> The fedora defect is:
> https://bugzilla.redhat.com/show_bug.cgi?id=1400623
>
>
> Thanks,
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
>
>
> _______________________________________________
> Nouveau mailing list
> Nouveau at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/nouveau
>
^ permalink raw reply
* Synopsys Ethernet QoS Driver
From: Pavel Machek @ 2016-12-07 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2eefdb8f-7e87-6009-6e50-c536d4b95dd6@synopsys.com>
Hi!
> > Thanks!
>
> Regarding this subject, I am thinking of making the following adaption:
>
> a) delete ethernet/synopsys
> b) rename ethernet/stmicro/stmmac to ethernet/synopsys
>
> and send you a patch for you to evaluate. Both agree with the approach?
> To have a new work base would be important, because I will add to the "new"
> structure some missing QoS features like Multichannel support, CBS
> and later TSN.
Rename should be the easy part. Please do that last.
Thanks,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161207/ec5e4ab2/attachment-0001.sig>
^ permalink raw reply
* [RESEND PATCH V6 0/6] Add support for privileged mappings
From: Sricharan @ 2016-12-07 9:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <ad7a90ce-c1cd-856e-8573-394c05fda6e4@arm.com>
Hi Robin,
>>> Hi Sricharan,
>>>
>>> On 02/12/16 14:55, Sricharan R wrote:
>>>> This series is a resend of the V5 that Mitch sent sometime back [2]
>>>> All the patches are the same and i have just rebased. Not sure why this
>>>> finally did not make it last time. The last patch in the previous
>>>> series does not apply now [3], so just redid that. Also Copied the tags
>>>> that he had from last time as well.
>>>
>>> Heh, I was assuming this would be down to me to pick up. Vinod did have
>>> some complaints last time about the commit message on the PL330 patch -
>>> I did get as far as rewriting that and reworking onto my SMMU
>>> changes[1], I just hadn't got round to sending it, so it fell onto the
>>> "after the next merge window" pile.
>>>
>>> I'd give some review comments, but they'd essentially be a diff against
>>> that branch :)
>>>
>>
>> Sure, i did not knew that you were on this already. I can repost with the diff
>> from your branch taken in or wait for you as well. I am fine with either ways
>> that you suggest.
>>
>> I checked the patches against your branch, i see that the changes are,
>>
>> 1) one patch for implementing it for armv7s descriptor
>> 2) Changes on pl330 patch commit logs and
>> 3) One patch for doing the revert on arm-smmuv3 as well.
>
>If you want to pick up my short-descriptor and SMMUv3 patches and run
>with them you're more than welcome - the rest is just cosmetic stuff
>which doesn't really matter, especially as it's picking up acks as-is.
>
Sure, i will repost with additional stuff picked up from your branch and
the acks as well.
Regards,
Sricharan
^ permalink raw reply
* [PATCH RFC] drm/sun4i: rgb: Add 5% tolerance to dot clock frequency check
From: Laurent Pinchart @ 2016-12-07 9:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v65uTH_PD28KqAhhzkE5zhLt54GUb7xXNxxe0xHW0A+xjQ@mail.gmail.com>
Hello,
On Wednesday 07 Dec 2016 10:26:25 Chen-Yu Tsai wrote:
> On Wed, Dec 7, 2016 at 1:29 AM, Maxime Ripard wrote:
> > On Thu, Nov 24, 2016 at 07:22:31PM +0800, Chen-Yu Tsai wrote:
> >> The panels shipped with Allwinner devices are very "generic", i.e.
> >> they do not have model numbers or reliable sources of information
> >> for the timings (that we know of) other than the fex files shipped
> >> on them. The dot clock frequency provided in the fex files have all
> >> been rounded to the nearest MHz, as that is the unit used in them.
> >>
> >> We were using the simple panel "urt,umsh-8596md-t" as a substitute
> >> for the A13 Q8 tablets in the absence of a specific model for what
> >> may be many different but otherwise timing compatible panels. This
> >> was usable without any visual artifacts or side effects, until the
> >> dot clock rate check was added in commit bb43d40d7c83 ("drm/sun4i:
> >> rgb: Validate the clock rate").
> >>
> >> The reason this check fails is because the dotclock frequency for
> >> this model is 33.26 MHz, which is not achievable with our dot clock
> >> hardware, and the rate returned by clk_round_rate deviates slightly,
> >> causing the driver to reject the display mode.
> >>
> >> The LCD panels have some tolerance on the dot clock frequency, even
> >> if it's not specified in their datasheets.
> >>
> >> This patch adds a 5% tolerence to the dot clock check.
> >
> > As we discussed already, I really believe this is just as arbitrary as
> > the current behaviour.
>
> Yes. I agree. This patch is mainly to give something that works for
> people who don't care about the details, and to get some feedback
> from people that do.
>
> > Some panels require an exact frequency,
There's no such thing as an exact frequency, there will always be some
tolerance (and if your display controller can really generate an exact
frequency I'd be very interested in that hardware :-)).
This is something that has been bugging me for some time now. The problem has
been mostly ignored, or worked around in different ways by different drivers.
I'm afraid I have no generic solution available, but I think we should try to
agree on a common behaviour.
I don't believe it would be reasonable to request each panel to report a
tolerance, as the value is most of the time not available from the
documentation (when documentation is available). Worse, I'm pretty sure that
most panels documented as fixed timing can actually accept a wide range of
timings. The timings reported in the datasheet are just the nominal values.
Panels that don't support multiple resolutions obviously require fixed active
h/v values. Even if they can tolerate some departure from the nominal timings
for the sync and porches lengths, it might not be very useful to support that
as I don't expect the display controllers and encoders to be a limiting factor
by not supporting the particular timings that a panel considers as nominal. On
the other hand, departing from the nominal pixel clock frequency is needed as
we can't achieve an exact match, and even possibly to have some control over
the frame rate (although that might also require changing the sync and porches
timings). Without specific information about panel tolerance, do we have any
option other than picking an arbitrary value ?
> > some have a minimal frequency
> > but no maximum, some have a maximum frequency but no minimal, and I
> > guess most of them deviates by how much exactly they can take (and
> > possibly can take more easily a higher frequency, but are less
> > tolerant if you take a frequency lower than the nominal.
> >
> > And we cannot remove that check entirely, since some bridges will
> > report out of range frequencies for higher modes that we know we
> > cannot reach.
>
> I believe this should be handled by the bridge driver in the check
> callback? The callback I'm changing is attached to the connector,
> which I think doesn't get used if you have a bridge instead.
> And this only checks the pre-registered display modes, such as
> those specified in simple-panel or EDID.
>
> > We could just try to see if the screen pixel clock frequency is out of
> > the pixel clock range we can generate, but then we will loop back on
> > how much out of range is it exactly, and is it within the screen
> > tolerancy.
> >
> > We have an API to deal with the panel tolerancies in the DRM panel
> > framework, we can (and should) use it.
>
> If you mean the get_timings callback, it's not very useful. Most of
> the panels in simple-panel do not use the display_timings structure,
> so they don't return anything. And I get that. The few datasheets
> I found don't list min/max tolerances for the dotclock.
>
> The ones that do have the min/max the same as the recommended value.
> This may or may not be accurate. IIRC the one panel that had this
> that I did check didn't list min/max values in its datasheet.
>
> > I'm not sure how others usually deal with this though. I think I
> > remember Eric telling me that for the RPi they just adjusted the
> > timings a bit, but they only really had a single panel to deal with.
> >
> > Daniel, Eric, Laurent, Sean? Any ideas?
>
> Yes! Feedback please! Between Maxime and me I think we only have a
> limited number of panels, with some overlap.
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [Nouveau] 4.9-rc7 nouveau fails on arm64 64k page kernel but works with 4k
From: Michel Dänzer @ 2016-12-07 9:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAAVeFuJc5y8M4Koj-Ge0XpK3PXVS-fnjrpUyD13skeBM1y_K1w@mail.gmail.com>
On 07/12/16 06:39 PM, Alexandre Courbot wrote:
> On Fri, Dec 2, 2016 at 12:23 PM, Ilia Mirkin <imirkin@alum.mit.edu> wrote:
>> That's right -- nouveau currently requires 4k page sizes to work. This is a
>> software limitation, not a hardware one though.
>
> Looking at the trace I wonder - is the limitation in Nouveau or in TTM?
Nouveau. Non-4K page sizes work fine with radeon (and presumably amdgpu).
--
Earthling Michel D?nzer | http://www.amd.com
Libre software enthusiast | Mesa and X developer
^ permalink raw reply
* [Nouveau] 4.9-rc7 nouveau fails on arm64 64k page kernel but works with 4k
From: Alexandre Courbot @ 2016-12-07 9:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d196c0c8-f429-4275-6246-a4e817b4bdf9@daenzer.net>
On Wed, Dec 7, 2016 at 6:53 PM, Michel D?nzer <michel@daenzer.net> wrote:
> On 07/12/16 06:39 PM, Alexandre Courbot wrote:
>> On Fri, Dec 2, 2016 at 12:23 PM, Ilia Mirkin <imirkin@alum.mit.edu> wrote:
>>> That's right -- nouveau currently requires 4k page sizes to work. This is a
>>> software limitation, not a hardware one though.
>>
>> Looking at the trace I wonder - is the limitation in Nouveau or in TTM?
>
> Nouveau. Non-4K page sizes work fine with radeon (and presumably amdgpu).
Thanks for the precision. I will check if Tegra iGPUs are also
affected by this - if they are then it gives me a good excuse to take
care of this bug.
^ permalink raw reply
* [PATCH v2] arm64: fpsimd: improve stacking logic in non-interruptible context
From: Ard Biesheuvel @ 2016-12-07 10:14 UTC (permalink / raw)
To: linux-arm-kernel
Currently, we allow kernel mode NEON in softirq or hardirq context by
stacking and unstacking a slice of the NEON register file for each call
to kernel_neon_begin() and kernel_neon_end(), respectively.
Given that
a) a CPU typically spends most of its time in userland, during which time
no kernel mode NEON in process context is in progress,
b) a CPU spends most of its time in the kernel doing other things than
kernel mode NEON when it gets interrupted to perform kernel mode NEON
in softirq context
the stacking and subsequent unstacking is only necessary if we are
interrupting a thread while it is performing kernel mode NEON in process
context, which means that in all other cases, we can simply preserve the
userland FPSIMD state once, and only restore it upon return to userland,
even if we are being invoked from softirq or hardirq context.
So instead of checking whether we are running in interrupt context, keep
track of the level of nested kernel mode NEON calls in progress, and only
perform the eager stack/unstack if the level exceeds 1.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
v2:
- BUG() on unexpected values of the nesting level
- relax the BUG() on num_regs>32 to a WARN, given that nothing actually
breaks in that case
arch/arm64/kernel/fpsimd.c | 48 ++++++++++++++------
1 file changed, 34 insertions(+), 14 deletions(-)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 394c61db5566..ae2c1bf569db 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -220,20 +220,35 @@ void fpsimd_flush_task_state(struct task_struct *t)
#ifdef CONFIG_KERNEL_MODE_NEON
-static DEFINE_PER_CPU(struct fpsimd_partial_state, hardirq_fpsimdstate);
-static DEFINE_PER_CPU(struct fpsimd_partial_state, softirq_fpsimdstate);
+/*
+ * Although unlikely, it is possible for three kernel mode NEON contexts to
+ * be live at the same time: process context, softirq context and hardirq
+ * context. So while the userland context is stashed in the thread's fpsimd
+ * state structure, we need two additional levels of storage.
+ */
+static DEFINE_PER_CPU(struct fpsimd_partial_state, nested_fpsimdstate[2]);
+static DEFINE_PER_CPU(int, kernel_neon_nesting_level);
/*
* Kernel-side NEON support functions
*/
void kernel_neon_begin_partial(u32 num_regs)
{
- if (in_interrupt()) {
- struct fpsimd_partial_state *s = this_cpu_ptr(
- in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
+ struct fpsimd_partial_state *s;
+ int level;
+
+ preempt_disable();
+
+ level = this_cpu_read(kernel_neon_nesting_level);
+ BUG_ON(level > 2);
+
+ if (level > 0) {
+ s = this_cpu_ptr(nested_fpsimdstate);
- BUG_ON(num_regs > 32);
- fpsimd_save_partial_state(s, roundup(num_regs, 2));
+ WARN_ON_ONCE(num_regs > 32);
+ num_regs = min(roundup(num_regs, 2), 32U);
+
+ fpsimd_save_partial_state(&s[level - 1], num_regs);
} else {
/*
* Save the userland FPSIMD state if we have one and if we
@@ -241,24 +256,29 @@ void kernel_neon_begin_partial(u32 num_regs)
* that there is no longer userland FPSIMD state in the
* registers.
*/
- preempt_disable();
if (current->mm &&
!test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
fpsimd_save_state(¤t->thread.fpsimd_state);
this_cpu_write(fpsimd_last_state, NULL);
}
+ this_cpu_write(kernel_neon_nesting_level, level + 1);
}
EXPORT_SYMBOL(kernel_neon_begin_partial);
void kernel_neon_end(void)
{
- if (in_interrupt()) {
- struct fpsimd_partial_state *s = this_cpu_ptr(
- in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
- fpsimd_load_partial_state(s);
- } else {
- preempt_enable();
+ struct fpsimd_partial_state *s;
+ int level;
+
+ level = this_cpu_read(kernel_neon_nesting_level) - 1;
+ BUG_ON(level < 0);
+
+ if (level > 0) {
+ s = this_cpu_ptr(nested_fpsimdstate);
+ fpsimd_load_partial_state(&s[level - 1]);
}
+ this_cpu_write(kernel_neon_nesting_level, level);
+ preempt_enable();
}
EXPORT_SYMBOL(kernel_neon_end);
--
2.7.4
^ permalink raw reply related
* [PATCH 3/8] rtc: add STM32 RTC driver
From: Amelie DELAUNAY @ 2016-12-07 10:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205163212.GA10458@linaro.org>
On 12/05/2016 05:32 PM, Mathieu Poirier wrote:
> On Mon, Dec 05, 2016 at 10:43:14AM +0100, Amelie DELAUNAY wrote:
>> Hi Mathieu,
>>
>> Thanks for reviewing
>>
>> On 12/02/2016 06:56 PM, Mathieu Poirier wrote:
>>> On Fri, Dec 02, 2016 at 03:09:56PM +0100, Amelie Delaunay wrote:
>>>> This patch adds support for the STM32 RTC.
>>>
>>> Hello Amelie,
>>>
>>>>
>>>> Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
>>>> ---
>>>> drivers/rtc/Kconfig | 10 +
>>>> drivers/rtc/Makefile | 1 +
>>>> drivers/rtc/rtc-stm32.c | 777
>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>> 3 files changed, 788 insertions(+)
>>>> create mode 100644 drivers/rtc/rtc-stm32.c
>>>>
>>>> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
>>>> index e859d14..dd8b218 100644
>>>> --- a/drivers/rtc/Kconfig
>>>> +++ b/drivers/rtc/Kconfig
>>>> @@ -1706,6 +1706,16 @@ config RTC_DRV_PIC32
>>>> This driver can also be built as a module. If so, the module
>>>> will be called rtc-pic32
>>>>
>>>> +config RTC_DRV_STM32
>>>> + tristate "STM32 On-Chip RTC"
>>>> + depends on ARCH_STM32
>>>> + help
>>>> + If you say yes here you get support for the STM32 On-Chip
>>>> + Real Time Clock.
>>>> +
>>>> + This driver can also be built as a module, if so, the module
>>>> + will be called "rtc-stm32".
>>>> +
>>>> comment "HID Sensor RTC drivers"
>>>>
>>>> config RTC_DRV_HID_SENSOR_TIME
>>>> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
>>>> index 1ac694a..87bd9cc 100644
>>>> --- a/drivers/rtc/Makefile
>>>> +++ b/drivers/rtc/Makefile
>>>> @@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
>>>> obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
>>>> obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
>>>> obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
>>>> +obj-$(CONFIG_RTC_DRV_STM32) += rtc-stm32.o
>>>> obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
>>>> obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
>>>> obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
>>>> diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
>>>> new file mode 100644
>>>> index 0000000..9e710ff
>>>> --- /dev/null
>>>> +++ b/drivers/rtc/rtc-stm32.c
>>>> @@ -0,0 +1,777 @@
>>>> +/*
>>>> + * Copyright (C) Amelie Delaunay 2015
>>>> + * Author: Amelie Delaunay <adelaunay.stm32@gmail.com>
>>>> + * License terms: GNU General Public License (GPL), version 2
>>>> + */
>>>> +
>>>> +#include <linux/bcd.h>
>>>> +#include <linux/clk.h>
>>>> +#include <linux/init.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/iopoll.h>
>>>> +#include <linux/ioport.h>
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/mfd/syscon.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_device.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/regmap.h>
>>>> +#include <linux/rtc.h>
>>>> +#include <linux/spinlock.h>
>>>> +
>>>> +#define DRIVER_NAME "stm32_rtc"
>>>> +
>>>> +/* STM32 RTC registers */
>>>> +#define STM32_RTC_TR 0x00
>>>> +#define STM32_RTC_DR 0x04
>>>> +#define STM32_RTC_CR 0x08
>>>> +#define STM32_RTC_ISR 0x0C
>>>> +#define STM32_RTC_PRER 0x10
>>>> +#define STM32_RTC_ALRMAR 0x1C
>>>> +#define STM32_RTC_WPR 0x24
>>>> +
>>>> +/* STM32_RTC_TR bit fields */
>>>> +#define STM32_RTC_TR_SEC_SHIFT 0
>>>> +#define STM32_RTC_TR_SEC GENMASK(6, 0)
>>>> +#define STM32_RTC_TR_MIN_SHIFT 8
>>>> +#define STM32_RTC_TR_MIN GENMASK(14, 8)
>>>> +#define STM32_RTC_TR_HOUR_SHIFT 16
>>>> +#define STM32_RTC_TR_HOUR GENMASK(21, 16)
>>>> +
>>>> +/* STM32_RTC_DR bit fields */
>>>> +#define STM32_RTC_DR_DATE_SHIFT 0
>>>> +#define STM32_RTC_DR_DATE GENMASK(5, 0)
>>>> +#define STM32_RTC_DR_MONTH_SHIFT 8
>>>> +#define STM32_RTC_DR_MONTH GENMASK(11, 8)
>>>> +#define STM32_RTC_DR_WDAY_SHIFT 13
>>>> +#define STM32_RTC_DR_WDAY GENMASK(15, 13)
>>>> +#define STM32_RTC_DR_YEAR_SHIFT 16
>>>> +#define STM32_RTC_DR_YEAR GENMASK(23, 16)
>>>> +
>>>> +/* STM32_RTC_CR bit fields */
>>>> +#define STM32_RTC_CR_FMT BIT(6)
>>>> +#define STM32_RTC_CR_ALRAE BIT(8)
>>>> +#define STM32_RTC_CR_ALRAIE BIT(12)
>>>> +
>>>> +/* STM32_RTC_ISR bit fields */
>>>> +#define STM32_RTC_ISR_ALRAWF BIT(0)
>>>> +#define STM32_RTC_ISR_INITS BIT(4)
>>>> +#define STM32_RTC_ISR_RSF BIT(5)
>>>> +#define STM32_RTC_ISR_INITF BIT(6)
>>>> +#define STM32_RTC_ISR_INIT BIT(7)
>>>> +#define STM32_RTC_ISR_ALRAF BIT(8)
>>>> +
>>>> +/* STM32_RTC_PRER bit fields */
>>>> +#define STM32_RTC_PRER_PRED_S_SHIFT 0
>>>> +#define STM32_RTC_PRER_PRED_S GENMASK(14, 0)
>>>> +#define STM32_RTC_PRER_PRED_A_SHIFT 16
>>>> +#define STM32_RTC_PRER_PRED_A GENMASK(22, 16)
>>>> +
>>>> +/* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */
>>>> +#define STM32_RTC_ALRMXR_SEC_SHIFT 0
>>>> +#define STM32_RTC_ALRMXR_SEC GENMASK(6, 0)
>>>> +#define STM32_RTC_ALRMXR_SEC_MASK BIT(7)
>>>> +#define STM32_RTC_ALRMXR_MIN_SHIFT 8
>>>> +#define STM32_RTC_ALRMXR_MIN GENMASK(14, 8)
>>>> +#define STM32_RTC_ALRMXR_MIN_MASK BIT(15)
>>>> +#define STM32_RTC_ALRMXR_HOUR_SHIFT 16
>>>> +#define STM32_RTC_ALRMXR_HOUR GENMASK(21, 16)
>>>> +#define STM32_RTC_ALRMXR_PM BIT(22)
>>>> +#define STM32_RTC_ALRMXR_HOUR_MASK BIT(23)
>>>> +#define STM32_RTC_ALRMXR_DATE_SHIFT 24
>>>> +#define STM32_RTC_ALRMXR_DATE GENMASK(29, 24)
>>>> +#define STM32_RTC_ALRMXR_WDSEL BIT(30)
>>>> +#define STM32_RTC_ALRMXR_WDAY_SHIFT 24
>>>> +#define STM32_RTC_ALRMXR_WDAY GENMASK(27, 24)
>>>> +#define STM32_RTC_ALRMXR_DATE_MASK BIT(31)
>>>> +
>>>> +/* STM32_RTC_WPR key constants */
>>>> +#define RTC_WPR_1ST_KEY 0xCA
>>>> +#define RTC_WPR_2ND_KEY 0x53
>>>> +#define RTC_WPR_WRONG_KEY 0xFF
>>>> +
>>>> +/*
>>>> + * RTC registers are protected agains parasitic write access.
>>>> + * PWR_CR_DBP bit must be set to enable write access to RTC registers.
>>>> + */
>>>> +/* STM32_PWR_CR */
>>>> +#define PWR_CR 0x00
>>>> +/* STM32_PWR_CR bit field */
>>>> +#define PWR_CR_DBP BIT(8)
>>>> +
>>>> +static struct regmap *dbp;
>>>> +
>>>> +struct stm32_rtc {
>>>> + struct rtc_device *rtc_dev;
>>>> + void __iomem *base;
>>>> + struct clk *pclk;
>>>> + struct clk *ck_rtc;
>>>> + unsigned int clksrc;
>>>> + spinlock_t lock; /* Protects registers accesses */
>>>> + int irq_alarm;
>>>> + struct regmap *pwrcr;
>>>> +};
>>>> +
>>>> +static inline unsigned int stm32_rtc_readl(struct stm32_rtc *rtc,
>>>> + unsigned int offset)
>>>> +{
>>>> + return readl_relaxed(rtc->base + offset);
>>>> +}
>>>> +
>>>> +static inline void stm32_rtc_writel(struct stm32_rtc *rtc,
>>>> + unsigned int offset, unsigned int value)
>>>> +{
>>>> + writel_relaxed(value, rtc->base + offset);
>>>> +}
>>>
>>> I'm not sure wrapping the readl/writel_relaxed function does anything
>> special
>>> other than simply redirecting the reader to another section of the code.
>> During development phase, it is useful to add debug traces but you're right,
>> this can be remove.
>>>
>>>> +
>>>> +static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
>>>> +{
>>>> +// if (dbp)
>>>> +// regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
>>>
>>> Did checkpatch let you get away with this? What did you intend to do
>> here?
>> Hum, as surprising as it may seem, checkpatch didn't complained about these
>> comments! But anyway, this has to be removed, it was a tentative to
>> enable/disable backup domain write protection any time we have to write in a
>> protected RTC register, but it is not functionnal. I have commented this
>> just to keep it in mind and forget to remove it before sending.
>>>
>>>> +
>>>> + stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_1ST_KEY);
>>>> + stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_2ND_KEY);
>>>> +}
>>>> +
>>>> +static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
>>>> +{
>>>> + stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_WRONG_KEY);
>>>> +
>>>> +// if (dbp)
>>>> +// regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
>>>> +}
>>>> +
>>>> +static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
>>>> +{
>>>> + unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
>>>> +
>>>> + if (!(isr & STM32_RTC_ISR_INITF)) {
>>>> + isr |= STM32_RTC_ISR_INIT;
>>>> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
>>>> +
>>>> + return readl_relaxed_poll_timeout_atomic(
>>>> + rtc->base + STM32_RTC_ISR,
>>>> + isr, (isr & STM32_RTC_ISR_INITF),
>>>> + 10, 100000);
>>>
>>> When using hard coded numerics please add comments that explains the
>> reason
>>> behind the selected values.
>> Sure. It takes around 2 RTCCLK clock cycles to enter in initialization phase
>> mode. So it depends on the frequency of the ck_rtc parent clock.
>> Either I keep parent clock frequency and compute the exact timeout, or I use
>> the "best and worst cases": slowest RTCCLK frequency is 32kHz, so it can
>> take up to 62us, highest RTCCLK frequency should be 1MHz, so it can take
>> only 2us. Polling every 10us with a timeout of 100ms seemed reasonable and
>> be a good compromise.
>
> I think this is a resonnable approach - please add that explanation as a comment
> in the code.
Ok I'll do that.
>
>>>
>>>> + }
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
>>>> +{
>>>> + unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
>>>> +
>>>> + isr &= ~STM32_RTC_ISR_INIT;
>>>> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
>>>> +}
>>>> +
>>>> +static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
>>>> +{
>>>> + unsigned int isr;
>>>> +
>>>> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
>>>> +
>>>> + isr &= ~STM32_RTC_ISR_RSF;
>>>> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
>>>> +
>>>> + /* Wait the registers to be synchronised */
>>>> + return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
>>>> + isr,
>>>> + (isr & STM32_RTC_ISR_RSF),
>>>> + 10, 100000);
>>>
>>> Shouldn't the break condition be !((isr & STM32_RTC_ISR_RSF) ? If not
>> this
>>> probably deserve a better comment.
>> RSF bit is set by hardware each time the calendar registers are synchronized
>> (it takes up to 2 RTCCLK). So the break condition is correct: we poll until
>> RSF flag is set or timeout is reached.
>>>
>>>> +}
>>>> +
>>>> +static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
>>>> +{
>>>> + struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
>>>> + unsigned long irqflags, events = 0;
>>>> + unsigned int isr, cr;
>>>> +
>>>> + spin_lock_irqsave(&rtc->lock, irqflags);
>>>> +
>>>> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
>>>> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
>>>> +
>>>> + if ((isr & STM32_RTC_ISR_ALRAF) &&
>>>> + (cr & STM32_RTC_CR_ALRAIE)) {
>>>> + /* Alarm A flag - Alarm interrupt */
>>>> + events |= RTC_IRQF | RTC_AF;
>>>> + isr &= ~STM32_RTC_ISR_ALRAF;
>>>> + }
>>>> +
>>>> + /* Clear event irqflags, otherwise new events won't be received */
>>>> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
>>>> +
>>>> + spin_unlock_irqrestore(&rtc->lock, irqflags);
>>>> +
>>>> + if (events) {
>>>> + dev_info(&rtc->rtc_dev->dev, "Alarm occurred\n");
>>>> +
>>>> + /* Pass event to the kernel */
>>>> + rtc_update_irq(rtc->rtc_dev, 1, events);
>>>> + return IRQ_HANDLED;
>>>> + } else {
>>>> + return IRQ_NONE;
>>>> + }
>>>> +}
>>>> +
>>>> +/* Convert rtc_time structure from bin to bcd format */
>>>> +static void tm2bcd(struct rtc_time *tm)
>>>> +{
>>>> + tm->tm_sec = bin2bcd(tm->tm_sec);
>>>> + tm->tm_min = bin2bcd(tm->tm_min);
>>>> + tm->tm_hour = bin2bcd(tm->tm_hour);
>>>> +
>>>> + tm->tm_mday = bin2bcd(tm->tm_mday);
>>>> + tm->tm_mon = bin2bcd(tm->tm_mon + 1);
>>>> + tm->tm_year = bin2bcd(tm->tm_year - 100);
>>>> + /*
>>>> + * Number of days since Sunday
>>>> + * - on kernel side, 0=Sunday...6=Saturday
>>>> + * - on rtc side, 0=invalid,1=Monday...7=Sunday
>>>> + */
>>>> + tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday;
>>>> +}
>>>> +
>>>> +/* Convert rtc_time structure from bcd to bin format */
>>>> +static void bcd2tm(struct rtc_time *tm)
>>>> +{
>>>> + tm->tm_sec = bcd2bin(tm->tm_sec);
>>>> + tm->tm_min = bcd2bin(tm->tm_min);
>>>> + tm->tm_hour = bcd2bin(tm->tm_hour);
>>>> +
>>>> + tm->tm_mday = bcd2bin(tm->tm_mday);
>>>> + tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
>>>> + tm->tm_year = bcd2bin(tm->tm_year) + 100;
>>>> + /*
>>>> + * Number of days since Sunday
>>>> + * - on kernel side, 0=Sunday...6=Saturday
>>>> + * - on rtc side, 0=invalid,1=Monday...7=Sunday
>>>> + */
>>>> + tm->tm_wday %= 7;
>>>> +}
>>>> +
>>>> +static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
>>>> +{
>>>> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
>>>> + unsigned int tr, dr;
>>>> + unsigned long irqflags;
>>>> +
>>>> + spin_lock_irqsave(&rtc->lock, irqflags);
>>>> +
>>>> + /* Time and Date in BCD format */
>>>> + tr = stm32_rtc_readl(rtc, STM32_RTC_TR);
>>>> + dr = stm32_rtc_readl(rtc, STM32_RTC_DR);
>>>> +
>>>> + spin_unlock_irqrestore(&rtc->lock, irqflags);
>>>> +
>>>> + tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
>>>> + tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
>>>> + tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
>>>> +
>>>> + tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
>>>> + tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
>>>> + tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
>>>> + tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT;
>>>> +
>>>> + /* We don't report tm_yday and tm_isdst */
>>>> +
>>>> + bcd2tm(tm);
>>>> +
>>>> + if (rtc_valid_tm(tm) < 0) {
>>>> + dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
>>>> + return -EINVAL;
>>>> + }
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
>>>> +{
>>>> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
>>>> + unsigned int tr, dr;
>>>> + unsigned long irqflags;
>>>> + int ret = 0;
>>>> +
>>>> + if (rtc_valid_tm(tm) < 0) {
>>>> + dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
>>>> + return -EINVAL;
>>>> + }
>>>> +
>>>> + tm2bcd(tm);
>>>> +
>>>> + /* Time in BCD format */
>>>> + tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) |
>>>> + ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) |
>>>> + ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR);
>>>> +
>>>> + /* Date in BCD format */
>>>> + dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE)
>> |
>>>> + ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH)
>> |
>>>> + ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR)
>> |
>>>> + ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY);
>>>> +
>>>> + spin_lock_irqsave(&rtc->lock, irqflags);
>>>> +
>>>> + stm32_rtc_wpr_unlock(rtc);
>>>> +
>>>> + ret = stm32_rtc_enter_init_mode(rtc);
>>>> + if (ret) {
>>>> + dev_err(dev, "Can't enter in init mode. Set time aborted.\n");
>>>> + goto end;
>>>> + }
>>>> +
>>>> + stm32_rtc_writel(rtc, STM32_RTC_TR, tr);
>>>> + stm32_rtc_writel(rtc, STM32_RTC_DR, dr);
>>>> +
>>>> + stm32_rtc_exit_init_mode(rtc);
>>>> +
>>>> + ret = stm32_rtc_wait_sync(rtc);
>>>> +end:
>>>> + stm32_rtc_wpr_lock(rtc);
>>>> +
>>>> + spin_unlock_irqrestore(&rtc->lock, irqflags);
>>>> +
>>>> + return ret;
>>>> +}
>>>> +
>>>> +static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm
>> *alrm)
>>>> +{
>>>> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
>>>> + struct rtc_time *tm = &alrm->time;
>>>> + unsigned int alrmar, cr, isr;
>>>> + unsigned long irqflags;
>>>> +
>>>> + spin_lock_irqsave(&rtc->lock, irqflags);
>>>> +
>>>> + alrmar = stm32_rtc_readl(rtc, STM32_RTC_ALRMAR);
>>>> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
>>>> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
>>>> +
>>>> + spin_unlock_irqrestore(&rtc->lock, irqflags);
>>>> +
>>>> + if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
>>>> + /*
>>>> + * Date/day don't care in Alarm comparison so alarm triggers
>>>> + * every day
>>>> + */
>>>> + tm->tm_mday = -1;
>>>> + tm->tm_wday = -1;
>>>> + } else {
>>>> + if (alrmar & STM32_RTC_ALRMXR_WDSEL) {
>>>> + /* Alarm is set to a day of week */
>>>> + tm->tm_mday = -1;
>>>> + tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >>
>>>> + STM32_RTC_ALRMXR_WDAY_SHIFT;
>>>> + tm->tm_wday %= 7;
>>>> + } else {
>>>> + /* Alarm is set to a day of month */
>>>> + tm->tm_wday = -1;
>>>> + tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >>
>>>> + STM32_RTC_ALRMXR_DATE_SHIFT;
>>>> + }
>>>> + }
>>>> +
>>>> + if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) {
>>>> + /* Hours don't care in Alarm comparison */
>>>> + tm->tm_hour = -1;
>>>> + } else {
>>>> + tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >>
>>>> + STM32_RTC_ALRMXR_HOUR_SHIFT;
>>>> + if (alrmar & STM32_RTC_ALRMXR_PM)
>>>> + tm->tm_hour += 12;
>>>> + }
>>>> +
>>>> + if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) {
>>>> + /* Minutes don't care in Alarm comparison */
>>>> + tm->tm_min = -1;
>>>> + } else {
>>>> + tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >>
>>>> + STM32_RTC_ALRMXR_MIN_SHIFT;
>>>> + }
>>>> +
>>>> + if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) {
>>>> + /* Seconds don't care in Alarm comparison */
>>>> + tm->tm_sec = -1;
>>>> + } else {
>>>> + tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >>
>>>> + STM32_RTC_ALRMXR_SEC_SHIFT;
>>>> + }
>>>> +
>>>> + bcd2tm(tm);
>>>> +
>>>> + alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
>>>> + alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0;
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int
>> enabled)
>>>> +{
>>>> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
>>>> + unsigned long irqflags;
>>>> + unsigned int isr, cr;
>>>> +
>>>> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
>>>
>>> Is the STM32_RTC_CR garanteed to be valid, i.e updated atomically? If not
>> this
>>> should probably be below the spinlock.
>> You're right.
>>>
>>>> +
>>>> + spin_lock_irqsave(&rtc->lock, irqflags);
>>>> +
>>>> + stm32_rtc_wpr_unlock(rtc);
>>>> +
>>>> + /* We expose Alarm A to the kernel */
>>>> + if (enabled)
>>>> + cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
>>>> + else
>>>> + cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
>>>> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
>>>> +
>>>> + /* Clear event irqflags, otherwise new events won't be received */
>>>> + isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
>>>> + isr &= ~STM32_RTC_ISR_ALRAF;
>>>> + stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
>>>> +
>>>> + stm32_rtc_wpr_lock(rtc);
>>>> +
>>>> + spin_unlock_irqrestore(&rtc->lock, irqflags);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm
>> *alrm)
>>>> +{
>>>> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
>>>> + struct rtc_time *tm = &alrm->time;
>>>> + unsigned long irqflags;
>>>> + unsigned int cr, isr, alrmar;
>>>> + int ret = 0;
>>>> +
>>>> + if (rtc_valid_tm(tm)) {
>>>> + dev_err(dev, "Alarm time not valid.\n");
>>>> + return -EINVAL;
>>>> + }
>>>> +
>>>> + tm2bcd(tm);
>>>> +
>>>> + spin_lock_irqsave(&rtc->lock, irqflags);
>>>> +
>>>> + stm32_rtc_wpr_unlock(rtc);
>>>> +
>>>> + /* Disable Alarm */
>>>> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
>>>> + cr &= ~STM32_RTC_CR_ALRAE;
>>>> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
>>>> +
>>>> + /* Poll Alarm write flag to be sure that Alarm update is allowed */
>>>> + ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
>>>> + isr,
>>>> + (isr & STM32_RTC_ISR_ALRAWF),
>>>> + 10, 100);
>>>> +
>>>> + if (ret) {
>>>> + dev_err(dev, "Alarm update not allowed\n");
>>>> + goto end;
>>>> + }
>>>> +
>>>> + alrmar = 0;
>>>> +
>>>> + if (tm->tm_mday < 0 && tm->tm_wday < 0) {
>>>> + /*
>>>> + * Date/day don't care in Alarm comparison so alarm triggers
>>>> + * every day
>>>> + */
>>>> + alrmar |= STM32_RTC_ALRMXR_DATE_MASK;
>>>> + } else {
>>>> + if (tm->tm_mday > 0) {
>>>> + /* Date is selected (ignoring wday) */
>>>> + alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
>>>> + STM32_RTC_ALRMXR_DATE;
>>>> + } else {
>>>> + /* Day of week is selected */
>>>> + int wday = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
>>>> +
>>>> + alrmar |= STM32_RTC_ALRMXR_WDSEL;
>>>> + alrmar |= (wday << STM32_RTC_ALRMXR_WDAY_SHIFT) &
>>>> + STM32_RTC_ALRMXR_WDAY;
>>>> + }
>>>> + }
>>>> +
>>>> + if (tm->tm_hour < 0) {
>>>> + /* Hours don't care in Alarm comparison */
>>>> + alrmar |= STM32_RTC_ALRMXR_HOUR_MASK;
>>>> + } else {
>>>> + /* 24-hour format */
>>>> + alrmar &= ~STM32_RTC_ALRMXR_PM;
>>>> + alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
>>>> + STM32_RTC_ALRMXR_HOUR;
>>>> + }
>>>> +
>>>> + if (tm->tm_min < 0) {
>>>> + /* Minutes don't care in Alarm comparison */
>>>> + alrmar |= STM32_RTC_ALRMXR_MIN_MASK;
>>>> + } else {
>>>> + alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
>>>> + STM32_RTC_ALRMXR_MIN;
>>>> + }
>>>> +
>>>> + if (tm->tm_sec < 0) {
>>>> + /* Seconds don't care in Alarm comparison */
>>>> + alrmar |= STM32_RTC_ALRMXR_SEC_MASK;
>>>> + } else {
>>>> + alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
>>>> + STM32_RTC_ALRMXR_SEC;
>>>> + }
>>>> +
>>>> + /* Write to Alarm register */
>>>> + stm32_rtc_writel(rtc, STM32_RTC_ALRMAR, alrmar);
>>>> +
>>>> + if (alrm->enabled)
>>>> + stm32_rtc_alarm_irq_enable(dev, 1);
>>>> + else
>>>> + stm32_rtc_alarm_irq_enable(dev, 0);
>>>> +
>>>> +end:
>>>> + stm32_rtc_wpr_lock(rtc);
>>>> +
>>>> + spin_unlock_irqrestore(&rtc->lock, irqflags);
>>>> +
>>>> + return ret;
>>>> +}
>>>> +
>>>> +static const struct rtc_class_ops stm32_rtc_ops = {
>>>> + .read_time = stm32_rtc_read_time,
>>>> + .set_time = stm32_rtc_set_time,
>>>> + .read_alarm = stm32_rtc_read_alarm,
>>>> + .set_alarm = stm32_rtc_set_alarm,
>>>> + .alarm_irq_enable = stm32_rtc_alarm_irq_enable,
>>>> +};
>>>> +
>>>> +#ifdef CONFIG_OF
>>>> +static const struct of_device_id stm32_rtc_of_match[] = {
>>>> + { .compatible = "st,stm32-rtc" },
>>>> + {}
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
>>>> +#endif
>>>> +
>>>> +static int stm32_rtc_init(struct platform_device *pdev,
>>>> + struct stm32_rtc *rtc)
>>>> +{
>>>> + unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
>>>> + unsigned int rate;
>>>> + unsigned long irqflags;
>>>> + int ret = 0;
>>>> +
>>>> + rate = clk_get_rate(rtc->ck_rtc);
>>>> +
>>>> + /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
>>>> + pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
>>>> + pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
>>>> +
>>>> + for (pred_a = pred_a_max; pred_a >= 0; pred_a--) {
>>>> + pred_s = (rate / (pred_a + 1)) - 1;
>>>> +
>>>> + if (((pred_s + 1) * (pred_a + 1)) == rate)
>>>> + break;
>>>> + }
>>>> +
>>>> + /*
>>>> + * Can't find a 1Hz, so give priority to RTC power consumption
>>>> + * by choosing the higher possible value for prediv_a
>>>> + */
>>>> + if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) {
>>>> + pred_a = pred_a_max;
>>>> + pred_s = (rate / (pred_a + 1)) - 1;
>>>> +
>>>> + dev_warn(&pdev->dev, "ck_rtc is %s\n",
>>>> + (rate - ((pred_a + 1) * (pred_s + 1)) < 0) ?
>>>> + "fast" : "slow");
>>>> + }
>>>> +
>>>> + spin_lock_irqsave(&rtc->lock, irqflags);
>>>> +
>>>> + stm32_rtc_wpr_unlock(rtc);
>>>> +
>>>> + ret = stm32_rtc_enter_init_mode(rtc);
>>>> + if (ret) {
>>>> + dev_err(&pdev->dev,
>>>> + "Can't enter in init mode. Prescaler config failed.\n");
>>>> + goto end;
>>>> + }
>>>> +
>>>> + prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) &
>> STM32_RTC_PRER_PRED_S;
>>>> + stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
>>>> + prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) &
>> STM32_RTC_PRER_PRED_A;
>>>> + stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
>>>> +
>>>> + /* Force 24h time format */
>>>> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
>>>> + cr &= ~STM32_RTC_CR_FMT;
>>>> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
>>>> +
>>>> + stm32_rtc_exit_init_mode(rtc);
>>>> +
>>>> + ret = stm32_rtc_wait_sync(rtc);
>>>> +
>>>> + if (stm32_rtc_readl(rtc, STM32_RTC_ISR) & STM32_RTC_ISR_INITS)
>>>> + dev_warn(&pdev->dev, "Date/Time must be initialized\n");
>>>> +end:
>>>> + stm32_rtc_wpr_lock(rtc);
>>>> +
>>>> + spin_unlock_irqrestore(&rtc->lock, irqflags);
>>>> +
>>>> + return ret;
>>>> +}
>>>> +
>>>> +static int stm32_rtc_probe(struct platform_device *pdev)
>>>> +{
>>>> + struct stm32_rtc *rtc;
>>>> + struct resource *res;
>>>> + int ret;
>>>> +
>>>> + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
>>>> + if (!rtc)
>>>> + return -ENOMEM;
>>>> +
>>>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>
>>> The value of 'res' should be checked before using it.
>> res is checked in devm_ioremap_resource just below :
>> if (!res || resource_type(res) != IORESOURCE_MEM) {
>> dev_err(dev, "invalid resource\n");
>> return IOMEM_ERR_PTR(-EINVAL);
>> }
>> That's why it is not checked here.
>>>
>>>> + rtc->base = devm_ioremap_resource(&pdev->dev, res);
>>>> + if (IS_ERR(rtc->base))
>>>> + return PTR_ERR(rtc->base);
>>>> +
>>>> + dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
>> "st,syscfg");
>>>> + if (IS_ERR(dbp)) {
>>>> + dev_err(&pdev->dev, "no st,syscfg\n");
>>>> + return PTR_ERR(dbp);
>>>> + }
>>>> +
>>>> + spin_lock_init(&rtc->lock);
>>>> +
>>>> + rtc->ck_rtc = devm_clk_get(&pdev->dev, "ck_rtc");
>>>> + if (IS_ERR(rtc->ck_rtc)) {
>>>> + dev_err(&pdev->dev, "no ck_rtc clock");
>>>> + return PTR_ERR(rtc->ck_rtc);
>>>> + }
>>>> +
>>>> + ret = clk_prepare_enable(rtc->ck_rtc);
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + if (dbp)
>>>> + regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
>>>
>>> The code above exits if there is a problem with the dbp, there is no point
>> in
>>> checking again.
>> You're right.
>>>
>>>> +
>>>> + ret = stm32_rtc_init(pdev, rtc);
>>>> + if (ret)
>>>> + goto err;
>>>> +
>>>> + rtc->irq_alarm = platform_get_irq_byname(pdev, "alarm");
>>>> + if (rtc->irq_alarm <= 0) {
>>>> + dev_err(&pdev->dev, "no alarm irq\n");
>>>> + ret = -ENOENT;
>>>> + goto err;
>>>> + }
>>>> +
>>>> + platform_set_drvdata(pdev, rtc);
>>>> +
>>>> + device_init_wakeup(&pdev->dev, true);
>>>
>>> What happens if device_init_wakeup() returns an error?
>> It means that RTC won't be able to wake up the board with RTC alarm. I can
>> add a warning for the user in this case ?
>
> Not really sure - it really depends on the kind of system will use this.
> For some not being able to wake up the board might a minor problem while
> for others a reason to fail the probing.
>
> Do we need a new binging for this, i.e one that would indicate this RTC can (and
> should) be able to wake up the board and fail driver probing if this can't be
> done?
>
> I'll let Alessandro and Alexander be the judge of that.
>
> Thanks,
> Mathieu
>
Ok, I wait for Alessandro and Alexandre advice to send a V2.
Thanks,
Amelie
>>>
>>>> +
>>>> + rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
>>>> + &stm32_rtc_ops, THIS_MODULE);
>>>> + if (IS_ERR(rtc->rtc_dev)) {
>>>> + ret = PTR_ERR(rtc->rtc_dev);
>>>> + dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
>>>> + ret);
>>>> + goto err;
>>>> + }
>>>> +
>>>> + /* Handle RTC alarm interrupts */
>>>> + ret = devm_request_irq(&pdev->dev, rtc->irq_alarm,
>>>> + stm32_rtc_alarm_irq, IRQF_TRIGGER_RISING,
>>>> + dev_name(&rtc->rtc_dev->dev), rtc);
>>>> + if (ret) {
>>>> + dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
>>>> + rtc->irq_alarm);
>>>> + goto err;
>>>> + }
>>>> +
>>>> + return 0;
>>>> +err:
>>>> + clk_disable_unprepare(rtc->ck_rtc);
>>>> +
>>>> + if (dbp)
>>>> + regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
>>>
>>> Same comment as above.
>> OK.
>>>
>>>> +
>>>> + device_init_wakeup(&pdev->dev, false);
>>>> +
>>>> + return ret;
>>>> +}
>>>> +
>>>> +static int __exit stm32_rtc_remove(struct platform_device *pdev)
>>>> +{
>>>> + struct stm32_rtc *rtc = platform_get_drvdata(pdev);
>>>> + unsigned int cr;
>>>> +
>>>> + /* Disable interrupts */
>>>> + stm32_rtc_wpr_unlock(rtc);
>>>> + cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
>>>> + cr &= ~STM32_RTC_CR_ALRAIE;
>>>> + stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
>>>> + stm32_rtc_wpr_lock(rtc);
>>>> +
>>>> + clk_disable_unprepare(rtc->ck_rtc);
>>>> +
>>>> + /* Enable backup domain write protection */
>>>> + if (dbp)
>>>> + regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
>>>> +
>>>> + device_init_wakeup(&pdev->dev, false);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int stm32_rtc_suspend(struct device *dev)
>>>> +{
>>>> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
>>>> +
>>>> + if (device_may_wakeup(dev))
>>>> + return enable_irq_wake(rtc->irq_alarm);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int stm32_rtc_resume(struct device *dev)
>>>> +{
>>>> + struct stm32_rtc *rtc = dev_get_drvdata(dev);
>>>> + int ret = 0;
>>>> +
>>>> + ret = stm32_rtc_wait_sync(rtc);
>>>> + if (ret < 0)
>>>> + return ret;
>>>> +
>>>> + if (device_may_wakeup(dev))
>>>> + return disable_irq_wake(rtc->irq_alarm);
>>>> +
>>>> + return ret;
>>>> +}
>>>> +#endif
>>>> +
>>>> +static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
>>>> + stm32_rtc_suspend, stm32_rtc_resume);
>>>> +
>>>> +static struct platform_driver stm32_rtc_driver = {
>>>> + .probe = stm32_rtc_probe,
>>>> + .remove = stm32_rtc_remove,
>>>> + .driver = {
>>>> + .name = DRIVER_NAME,
>>>> + .pm = &stm32_rtc_pm_ops,
>>>> + .of_match_table = stm32_rtc_of_match,
>>>> + },
>>>> +};
>>>> +
>>>> +module_platform_driver(stm32_rtc_driver);
>>>> +
>>>> +MODULE_ALIAS("platform:" DRIVER_NAME);
>>>> +MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
>>>> +MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
>>>> +MODULE_LICENSE("GPL v2");
>>>> --
>>>> 1.9.1
>>>>
>>
>> Best regards,
>> Amelie
>>
^ permalink raw reply
* [PATCH v2] PCI: designware: add host_init error handling
From: Srinivas Kandagatla @ 2016-12-07 10:32 UTC (permalink / raw)
To: linux-arm-kernel
This patch add support to return value from host_init() callback from drivers,
so that the designware libary can handle or pass it to proper place. Issue with
void return type is that errors or error handling within host_init() callback
are never know to designware code, which could go ahead and access registers
even in error cases.
Typical case in qcom controller driver is to turn off clks in case of errors,
if designware code continues to read/write register when clocks are turned off
the board would reboot/lockup.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
Currently designware code does not have a way return errors generated
as part of host_init() callback in controller drivers. This is an issue
with controller drivers like qcom which turns off the clocks in error
handling path. As the dw core is un aware of this would continue to
access registers which faults resulting in board reboots/hangs.
There are two ways to solve this issue,
one is remove error handling in the qcom controller host_init() function
other is to handle error and pass back to dw core code which would then
pass back to controller driver as part of dw_pcie_host_init() return value.
Second option seems more sensible and correct way to fix the issue,
this patch does the same.
As part of this change to host_init() return type I had to patch other
ihost controller drivers which use dw core. Most of the changes to other drivers
are to return proper error codes to upper layer.
Only compile tested drivers.
Changes since RFC:
- Add error handling to other drivers as suggested by Joao Pinto
drivers/pci/host/pci-dra7xx.c | 10 ++++++++--
drivers/pci/host/pci-exynos.c | 10 ++++++++--
drivers/pci/host/pci-imx6.c | 10 ++++++++--
drivers/pci/host/pci-keystone.c | 10 ++++++++--
drivers/pci/host/pci-layerscape.c | 22 +++++++++++++---------
drivers/pci/host/pcie-armada8k.c | 4 +++-
drivers/pci/host/pcie-designware-plat.c | 10 ++++++++--
drivers/pci/host/pcie-designware.c | 4 +++-
drivers/pci/host/pcie-designware.h | 2 +-
drivers/pci/host/pcie-qcom.c | 5 +++--
drivers/pci/host/pcie-spear13xx.c | 10 ++++++++--
11 files changed, 71 insertions(+), 26 deletions(-)
diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c
index 9595fad..811f0f9 100644
--- a/drivers/pci/host/pci-dra7xx.c
+++ b/drivers/pci/host/pci-dra7xx.c
@@ -127,9 +127,10 @@ static void dra7xx_pcie_enable_interrupts(struct dra7xx_pcie *dra7xx)
LEG_EP_INTERRUPTS);
}
-static void dra7xx_pcie_host_init(struct pcie_port *pp)
+static int dra7xx_pcie_host_init(struct pcie_port *pp)
{
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+ int ret;
pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR;
pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR;
@@ -138,10 +139,15 @@ static void dra7xx_pcie_host_init(struct pcie_port *pp)
dw_pcie_setup_rc(pp);
- dra7xx_pcie_establish_link(dra7xx);
+ ret = dra7xx_pcie_establish_link(dra7xx);
+ if (ret < 0)
+ return ret;
+
if (IS_ENABLED(CONFIG_PCI_MSI))
dw_pcie_msi_init(pp);
dra7xx_pcie_enable_interrupts(dra7xx);
+
+ return 0;
}
static struct pcie_host_ops dra7xx_pcie_host_ops = {
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index f1c544b..c116fd9 100644
--- a/drivers/pci/host/pci-exynos.c
+++ b/drivers/pci/host/pci-exynos.c
@@ -458,12 +458,18 @@ static int exynos_pcie_link_up(struct pcie_port *pp)
return 0;
}
-static void exynos_pcie_host_init(struct pcie_port *pp)
+static int exynos_pcie_host_init(struct pcie_port *pp)
{
struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+ int ret;
+
+ ret = exynos_pcie_establish_link(exynos_pcie);
+ if (ret < 0)
+ return ret;
- exynos_pcie_establish_link(exynos_pcie);
exynos_pcie_enable_interrupts(exynos_pcie);
+
+ return 0;
}
static struct pcie_host_ops exynos_pcie_host_ops = {
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index c8cefb0..1251e92 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -550,18 +550,24 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
return ret;
}
-static void imx6_pcie_host_init(struct pcie_port *pp)
+static int imx6_pcie_host_init(struct pcie_port *pp)
{
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+ int ret;
imx6_pcie_assert_core_reset(imx6_pcie);
imx6_pcie_init_phy(imx6_pcie);
imx6_pcie_deassert_core_reset(imx6_pcie);
dw_pcie_setup_rc(pp);
- imx6_pcie_establish_link(imx6_pcie);
+ ret = imx6_pcie_establish_link(imx6_pcie);
+
+ if (ret < 0)
+ return ret;
if (IS_ENABLED(CONFIG_PCI_MSI))
dw_pcie_msi_init(pp);
+
+ return 0;
}
static int imx6_pcie_link_up(struct pcie_port *pp)
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
index 043c19a..4067a75 100644
--- a/drivers/pci/host/pci-keystone.c
+++ b/drivers/pci/host/pci-keystone.c
@@ -260,12 +260,16 @@ static int keystone_pcie_fault(unsigned long addr, unsigned int fsr,
return 0;
}
-static void __init ks_pcie_host_init(struct pcie_port *pp)
+static int __init ks_pcie_host_init(struct pcie_port *pp)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
u32 val;
+ int ret;
+
+ ret = ks_pcie_establish_link(ks_pcie);
+ if (ret < 0)
+ return ret;
- ks_pcie_establish_link(ks_pcie);
ks_dw_pcie_setup_rc_app_regs(ks_pcie);
ks_pcie_setup_interrupts(ks_pcie);
writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
@@ -287,6 +291,8 @@ static void __init ks_pcie_host_init(struct pcie_port *pp)
*/
hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
"Asynchronous external abort");
+
+ return 0;
}
static struct pcie_host_ops keystone_pcie_host_ops = {
diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c
index 6537079..60c8b84 100644
--- a/drivers/pci/host/pci-layerscape.c
+++ b/drivers/pci/host/pci-layerscape.c
@@ -103,30 +103,32 @@ static int ls1021_pcie_link_up(struct pcie_port *pp)
return 1;
}
-static void ls1021_pcie_host_init(struct pcie_port *pp)
+static int ls1021_pcie_host_init(struct pcie_port *pp)
{
struct device *dev = pp->dev;
struct ls_pcie *pcie = to_ls_pcie(pp);
u32 index[2];
+ int ret;
pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node,
"fsl,pcie-scfg");
if (IS_ERR(pcie->scfg)) {
dev_err(dev, "No syscfg phandle specified\n");
- pcie->scfg = NULL;
- return;
+ return PTR_ERR(pcie->scfg);
}
- if (of_property_read_u32_array(dev->of_node,
- "fsl,pcie-scfg", index, 2)) {
- pcie->scfg = NULL;
- return;
- }
+ ret = of_property_read_u32_array(dev->of_node,
+ "fsl,pcie-scfg", index, 2);
+ if (ret < 0)
+ return ret;
+
pcie->index = index[1];
dw_pcie_setup_rc(pp);
ls_pcie_drop_msg_tlp(pcie);
+
+ return 0;
}
static int ls_pcie_link_up(struct pcie_port *pp)
@@ -144,7 +146,7 @@ static int ls_pcie_link_up(struct pcie_port *pp)
return 1;
}
-static void ls_pcie_host_init(struct pcie_port *pp)
+static int ls_pcie_host_init(struct pcie_port *pp)
{
struct ls_pcie *pcie = to_ls_pcie(pp);
@@ -153,6 +155,8 @@ static void ls_pcie_host_init(struct pcie_port *pp)
ls_pcie_clear_multifunction(pcie);
ls_pcie_drop_msg_tlp(pcie);
iowrite32(0, pcie->pp.dbi_base + PCIE_DBI_RO_WR_EN);
+
+ return 0;
}
static int ls_pcie_msi_host_init(struct pcie_port *pp,
diff --git a/drivers/pci/host/pcie-armada8k.c b/drivers/pci/host/pcie-armada8k.c
index 0ac0f18..29bdd8b 100644
--- a/drivers/pci/host/pcie-armada8k.c
+++ b/drivers/pci/host/pcie-armada8k.c
@@ -134,12 +134,14 @@ static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
dev_err(pp->dev, "Link not up after reconfiguration\n");
}
-static void armada8k_pcie_host_init(struct pcie_port *pp)
+static int armada8k_pcie_host_init(struct pcie_port *pp)
{
struct armada8k_pcie *pcie = to_armada8k_pcie(pp);
dw_pcie_setup_rc(pp);
armada8k_pcie_establish_link(pcie);
+
+ return 0;
}
static irqreturn_t armada8k_pcie_irq_handler(int irq, void *arg)
diff --git a/drivers/pci/host/pcie-designware-plat.c b/drivers/pci/host/pcie-designware-plat.c
index 1a02038..e01adbb 100644
--- a/drivers/pci/host/pcie-designware-plat.c
+++ b/drivers/pci/host/pcie-designware-plat.c
@@ -35,13 +35,19 @@ static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg)
return dw_handle_msi_irq(pp);
}
-static void dw_plat_pcie_host_init(struct pcie_port *pp)
+static int dw_plat_pcie_host_init(struct pcie_port *pp)
{
+ int ret;
+
dw_pcie_setup_rc(pp);
- dw_pcie_wait_for_link(pp);
+ ret = dw_pcie_wait_for_link(pp);
+ if (ret)
+ return ret;
if (IS_ENABLED(CONFIG_PCI_MSI))
dw_pcie_msi_init(pp);
+
+ return 0;
}
static struct pcie_host_ops dw_plat_pcie_host_ops = {
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index bed1999..4a81b72 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -638,7 +638,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
}
if (pp->ops->host_init)
- pp->ops->host_init(pp);
+ ret = pp->ops->host_init(pp);
+ if (ret < 0)
+ goto error;
pp->root_bus_nr = pp->busn->start;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index a567ea2..eacf18f 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -63,7 +63,7 @@ struct pcie_host_ops {
int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
unsigned int devfn, int where, int size, u32 val);
int (*link_up)(struct pcie_port *pp);
- void (*host_init)(struct pcie_port *pp);
+ int (*host_init)(struct pcie_port *pp);
void (*msi_set_irq)(struct pcie_port *pp, int irq);
void (*msi_clear_irq)(struct pcie_port *pp, int irq);
phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
diff --git a/drivers/pci/host/pcie-qcom.c b/drivers/pci/host/pcie-qcom.c
index 3593640..7d5fb38 100644
--- a/drivers/pci/host/pcie-qcom.c
+++ b/drivers/pci/host/pcie-qcom.c
@@ -429,7 +429,7 @@ static int qcom_pcie_link_up(struct pcie_port *pp)
return !!(val & PCI_EXP_LNKSTA_DLLLA);
}
-static void qcom_pcie_host_init(struct pcie_port *pp)
+static int qcom_pcie_host_init(struct pcie_port *pp)
{
struct qcom_pcie *pcie = to_qcom_pcie(pp);
int ret;
@@ -455,12 +455,13 @@ static void qcom_pcie_host_init(struct pcie_port *pp)
if (ret)
goto err;
- return;
+ return ret;
err:
qcom_ep_reset_assert(pcie);
phy_power_off(pcie->phy);
err_deinit:
pcie->ops->deinit(pcie);
+ return ret;
}
static int qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c
index 3cf197b..2408f80 100644
--- a/drivers/pci/host/pcie-spear13xx.c
+++ b/drivers/pci/host/pcie-spear13xx.c
@@ -174,12 +174,18 @@ static int spear13xx_pcie_link_up(struct pcie_port *pp)
return 0;
}
-static void spear13xx_pcie_host_init(struct pcie_port *pp)
+static int spear13xx_pcie_host_init(struct pcie_port *pp)
{
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp);
+ int ret;
+
+ ret = spear13xx_pcie_establish_link(spear13xx_pcie);
+ if (ret < 0)
+ return ret;
- spear13xx_pcie_establish_link(spear13xx_pcie);
spear13xx_pcie_enable_interrupts(spear13xx_pcie);
+
+ return 0;
}
static struct pcie_host_ops spear13xx_pcie_host_ops = {
--
2.7.4
^ permalink raw reply related
* [Question] New mmap64 syscall?
From: Yury Norov @ 2016-12-07 10:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3014428.VXGdOARdm1@wuerfel>
On Tue, Dec 06, 2016 at 10:20:20PM +0100, Arnd Bergmann wrote:
> On Wednesday, December 7, 2016 12:24:40 AM CET Yury Norov wrote:
> > 3. Introduce new mmap64() syscall like this:
> > sys_mmap64(void *addr, size_t len, int prot, int flags, int fd, struct off_pair *off);
> > (The pointer here because otherwise we have 7 args, if simply pass off_hi and
> > off_lo in registers.)
>
> This wouldn't have to be a pair, just a pointer to a 64-bit number.
>
> > With new 64-bit interface we can deprecate mmap2(), and generalize all
> > implementations in kernel.
> >
> > I think we can discuss it because 64-bit is the default size for off_t
> > in all new 32-bit architectures. So generic solution may take place.
> >
> > The last question here is how important to support offsets bigger than
> > 2^44 on 32-bit machines in practice? It may be a case for ARM64 servers,
> > which are looking like main aarch64/ilp32 users. If no, we can leave
> > things as is, and just do nothing.
>
> If there is a use case for larger than 16TB offsets, we should add
> the call on all architectures, probably using your approach 3. I don't
> think that we should treat it as anything special for arm64 though.
>From this point of view, 16+TB offset is a matter of 16+TB storage,
and it's more than real. The other consideration to add it is that
we have 64-bit support for offsets in syscalls like sys_llseek().
So mmap64() will simply extend this support.
I can prepare this patch. Some implementation details I'd like to
clarify:
Syscall declaration:
SYSCALL_DEFINE6(mmap64, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags,
unsigned long, fd, unsigned long long *, offset);
sys_mmap64() deprecates sys_mmap2(), and __ARCH_WANT_MMAP2 is
introduced to keep it enabled for all existing architectures.
All modern arches (aarch64/ilp32 is the first candidate) will have
mmap64() only. The example is set/getrlimit() or renameat() drop
patches (b0da6d44).
On GLIBC side, __OFF_T_MATCHES_OFF64_t will wire mmap() from
linux/generic/wordsize32/mmap.c to mmap64() from linux/mmap64.c.
mmap64() will first try __NR_mmap64, and if not defined, or ENOSYS
is returned, __NR_mmap2 will be called. This is to let userspace that
supports both mmap2() and mmap64() have full 64-bit offset support, not
44-bit one.
For __NR_mmap2 case, I'd also add the check against offsets more than
2^44, and set errno to EOVERFLOW in that case.
Any thoughts?
Yury.
^ permalink raw reply
* [PATCH] usb: gadget: udc: atmel: Fix check in usba_ep_enable()
From: Boris Brezillon @ 2016-12-07 10:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481061583-4727-1-git-send-email-boris.brezillon@free-electrons.com>
On Tue, 6 Dec 2016 22:59:43 +0100
Boris Brezillon <boris.brezillon@free-electrons.com> wrote:
> desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK is not necessarily
> equal to ep->index and that's perfectly fine. The usba endpoint index is
> just an internal identifier used by the driver to know which registers
> to use for a USB endpoint.
>
> Enforcing this constraint is not only useless, but can also lead to
> errors since nothing guarantees that the endpoint number and index are
> matching when an endpoint is selected for a specific descriptor, thus
> leading to errors at ->enable() time when it's already too late to choose
> another endpoint.
Please ignore this patch. The real bug has been fixed in commit
bbe097f092b0 ("usb: gadget: udc: atmel: fix endpoint name").
>
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> ---
> Hi,
>
> I intentionally didn't add the Cc stable and Fixes tags because this
> bug dates back to the drivers creation, and I fear the index <->
> epnum constraint was actually required at that time.
>
> Note that I discovered this bug thanks to the WARN_ON_ONCE() in
> usb_ep_queue() [1] which was introduced in 4.5.
> It might appear that this problem was silently ignored before that
> (with part of the usba_ep_enable() code being skipped without any
> notice).
>
> Regards,
>
> Boris
>
> [1]http://lxr.free-electrons.com/source/drivers/usb/gadget/udc/core.c#L264
> ---
> drivers/usb/gadget/udc/atmel_usba_udc.c | 7 ++-----
> 1 file changed, 2 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
> index bb1f6c8f0f01..981d2639d413 100644
> --- a/drivers/usb/gadget/udc/atmel_usba_udc.c
> +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
> @@ -531,11 +531,8 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
>
> maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
>
> - if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
> - || ep->index == 0
> - || desc->bDescriptorType != USB_DT_ENDPOINT
> - || maxpacket == 0
> - || maxpacket > ep->fifo_size) {
> + if (ep->index == 0 || desc->bDescriptorType != USB_DT_ENDPOINT ||
> + maxpacket == 0 || maxpacket > ep->fifo_size) {
> DBG(DBG_ERR, "ep_enable: Invalid argument");
> return -EINVAL;
> }
^ permalink raw reply
* [PATCH 2/7] arm: ftrace: Add call modify mechanism
From: kbuild test robot @ 2016-12-07 10:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481043967-15602-3-git-send-email-abelvesa@linux.com>
Hi Abel,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9-rc8 next-20161206]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Abel-Vesa/arm-Add-livepatch-support/20161207-074210
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm
Note: the linux-review/Abel-Vesa/arm-Add-livepatch-support/20161207-074210 HEAD 49113edc744f38a682a4afa9e904384bb00f2988 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
>> arch/arm/kernel/ftrace.c:163:5: error: redefinition of 'ftrace_modify_call'
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
^~~~~~~~~~~~~~~~~~
In file included from arch/arm/kernel/ftrace.c:15:0:
include/linux/ftrace.h:595:19: note: previous definition of 'ftrace_modify_call' was here
static inline int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
^~~~~~~~~~~~~~~~~~
vim +/ftrace_modify_call +163 arch/arm/kernel/ftrace.c
157 }
158 #endif
159
160 return ret;
161 }
162
> 163 int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
164 unsigned long addr)
165 {
166 unsigned long pc = rec->ip;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 59384 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161207/a5fd880a/attachment-0001.gz>
^ permalink raw reply
* [PATCH v5 0/4] ARM: dts: da850: tilcdc related DT changes
From: Bartosz Golaszewski @ 2016-12-07 10:42 UTC (permalink / raw)
To: linux-arm-kernel
This series contains the last DT changes required for LCDC support
on da850-lcdk. The first one adds the dumb-vga-dac nodes, the second
limits the maximum pixel clock rate.
v1 -> v2:
- drop patch 3/3 (already merged)
- use max-pixelclock instead of max-bandwidth for display mode limiting
v2 -> v3:
- make the commit message in patch [2/2] more detailed
- move the max-pixelclock property to da850.dtsi as the limit
affects all da850-based boards
v3 -> v4:
- remove the input port from the display node
- move the display ports node to da850-lcdk.dts
- rename the vga_bridge node to vga-bridge
- move the LCDC pins to the LCDC node (from the vga bridge node)
v4 -> v5:
- rename the display label to lcdc
- instead of using the 'dumb-vga-dac' compatible, add bindings for
ti,ths8135 and use it as the vga-bridge node compatible
Bartosz Golaszewski (4):
ARM: dts: da850: rename the display node label
drm: bridge: add support for TI ths8135
ARM: dts: da850-lcdk: add the vga-bridge node
ARM: dts: da850: specify the maximum pixel clock rate for tilcdc
.../bindings/display/bridge/ti,ths8135.txt | 52 +++++++++++++++++
arch/arm/boot/dts/da850-lcdk.dts | 67 ++++++++++++++++++++++
arch/arm/boot/dts/da850.dtsi | 3 +-
drivers/gpu/drm/bridge/dumb-vga-dac.c | 1 +
4 files changed, 122 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
--
2.9.3
^ permalink raw reply
* [PATCH v5 1/4] ARM: dts: da850: rename the display node label
From: Bartosz Golaszewski @ 2016-12-07 10:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481107365-24839-1-git-send-email-bgolaszewski@baylibre.com>
The tilcdc node name is 'display' as per the ePAPR 1.1 recommendation.
The label is also 'display', but change it to 'lcdc' to make it clear
what the underlying hardware is.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
arch/arm/boot/dts/da850.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index ffc6e1a..3f51e59 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -448,7 +448,7 @@
dma-names = "tx", "rx";
};
- display: display at 213000 {
+ lcdc: display at 213000 {
compatible = "ti,da850-tilcdc";
reg = <0x213000 0x1000>;
interrupts = <52>;
--
2.9.3
^ permalink raw reply related
* [PATCH v5 2/4] drm: bridge: add support for TI ths8135
From: Bartosz Golaszewski @ 2016-12-07 10:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481107365-24839-1-git-send-email-bgolaszewski@baylibre.com>
THS8135 is a configurable video DAC. Add DT bindings for this chip and
use the dumb-vga-dac driver for now as no configuration is required to
make it work.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
.../bindings/display/bridge/ti,ths8135.txt | 52 ++++++++++++++++++++++
drivers/gpu/drm/bridge/dumb-vga-dac.c | 1 +
2 files changed, 53 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
new file mode 100644
index 0000000..23cd8ee
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
@@ -0,0 +1,52 @@
+THS8135 Video DAC
+-----------------
+
+This is the binding for Texas Instruments THS8135 Video DAC bridge.
+
+Required properties:
+
+- compatible: Must be "ti,ths8135"
+
+Required nodes:
+
+This device has two video ports. Their connections are modelled using the OF
+graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 for RGB input
+- Video port 1 for VGA output
+
+Example
+-------
+
+vga-bridge {
+ compatible = "ti,ths8135";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port at 0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ vga_bridge_in: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&lcdc_out_vga>;
+ };
+ };
+
+ port at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ vga_bridge_out: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&vga_con_in>;
+ };
+ };
+ };
+};
diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
index afec232..498fa75 100644
--- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
+++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
@@ -204,6 +204,7 @@ static int dumb_vga_remove(struct platform_device *pdev)
static const struct of_device_id dumb_vga_match[] = {
{ .compatible = "dumb-vga-dac" },
+ { .compatible = "ti,ths8135" },
{},
};
MODULE_DEVICE_TABLE(of, dumb_vga_match);
--
2.9.3
^ permalink raw reply related
* [PATCH v5 3/4] ARM: dts: da850-lcdk: add the vga-bridge node
From: Bartosz Golaszewski @ 2016-12-07 10:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481107365-24839-1-git-send-email-bgolaszewski@baylibre.com>
Add the vga-bridge node to the board DT together with corresponding
ports and vga connector. This allows to retrieve the edid info from
the display automatically.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
arch/arm/boot/dts/da850-lcdk.dts | 67 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/arch/arm/boot/dts/da850-lcdk.dts b/arch/arm/boot/dts/da850-lcdk.dts
index afcb482..39602eb 100644
--- a/arch/arm/boot/dts/da850-lcdk.dts
+++ b/arch/arm/boot/dts/da850-lcdk.dts
@@ -51,6 +51,51 @@
system-clock-frequency = <24576000>;
};
};
+
+ vga-bridge {
+ compatible = "ti,ths8135";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port at 0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ vga_bridge_in: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&lcdc_out_vga>;
+ };
+ };
+
+ port at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ vga_bridge_out: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&vga_con_in>;
+ };
+ };
+ };
+ };
+
+ vga {
+ compatible = "vga-connector";
+
+ ddc-i2c-bus = <&i2c0>;
+
+ port {
+ vga_con_in: endpoint {
+ remote-endpoint = <&vga_bridge_out>;
+ };
+ };
+ };
};
&pmx_core {
@@ -236,3 +281,25 @@
&memctrl {
status = "okay";
};
+
+&lcdc {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcd_pins>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ lcdc_out: port at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ lcdc_out_vga: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&vga_bridge_in>;
+ };
+ };
+ };
+};
--
2.9.3
^ permalink raw reply related
* [PATCH v5 4/4] ARM: dts: da850: specify the maximum pixel clock rate for tilcdc
From: Bartosz Golaszewski @ 2016-12-07 10:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481107365-24839-1-git-send-email-bgolaszewski@baylibre.com>
At maximum CPU frequency of 300 MHz the maximum pixel clock frequency
is 37.5 MHz[1]. We must filter out any mode for which the calculated
pixel clock rate would exceed this value.
Specify the max-pixelclock property for the display node for
da850-lcdk.
[1] http://processors.wiki.ti.com/index.php/OMAP-L1x/C674x/AM1x_LCD_Controller_(LCDC)_Throughput_and_Optimization_Techniques
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
arch/arm/boot/dts/da850.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 3f51e59..ba5bf80 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -452,6 +452,7 @@
compatible = "ti,da850-tilcdc";
reg = <0x213000 0x1000>;
interrupts = <52>;
+ max-pixelclock = <37500>;
status = "disabled";
};
};
--
2.9.3
^ permalink raw reply related
* [PATCH v5 2/4] drm: bridge: add support for TI ths8135
From: Bartosz Golaszewski @ 2016-12-07 10:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481107365-24839-3-git-send-email-bgolaszewski@baylibre.com>
2016-12-07 11:42 GMT+01:00 Bartosz Golaszewski <bgolaszewski@baylibre.com>:
> THS8135 is a configurable video DAC. Add DT bindings for this chip and
> use the dumb-vga-dac driver for now as no configuration is required to
> make it work.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
> .../bindings/display/bridge/ti,ths8135.txt | 52 ++++++++++++++++++++++
> drivers/gpu/drm/bridge/dumb-vga-dac.c | 1 +
> 2 files changed, 53 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
>
> diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
> new file mode 100644
> index 0000000..23cd8ee
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
> @@ -0,0 +1,52 @@
> +THS8135 Video DAC
> +-----------------
> +
> +This is the binding for Texas Instruments THS8135 Video DAC bridge.
> +
> +Required properties:
> +
> +- compatible: Must be "ti,ths8135"
> +
> +Required nodes:
> +
> +This device has two video ports. Their connections are modelled using the OF
> +graph bindings specified in Documentation/devicetree/bindings/graph.txt.
> +
> +- Video port 0 for RGB input
> +- Video port 1 for VGA output
> +
> +Example
> +-------
> +
> +vga-bridge {
> + compatible = "ti,ths8135";
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + port at 0 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0>;
> +
> + vga_bridge_in: endpoint at 0 {
> + reg = <0>;
> + remote-endpoint = <&lcdc_out_vga>;
> + };
> + };
> +
> + port at 1 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <1>;
> +
> + vga_bridge_out: endpoint at 0 {
> + reg = <0>;
> + remote-endpoint = <&vga_con_in>;
> + };
> + };
> + };
> +};
> diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
> index afec232..498fa75 100644
> --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
> +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
> @@ -204,6 +204,7 @@ static int dumb_vga_remove(struct platform_device *pdev)
>
> static const struct of_device_id dumb_vga_match[] = {
> { .compatible = "dumb-vga-dac" },
> + { .compatible = "ti,ths8135" },
> {},
> };
> MODULE_DEVICE_TABLE(of, dumb_vga_match);
> --
> 2.9.3
>
+ Maxime
Sorry, I forgot to include your e-mail.
Bartosz
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox