Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 2/7] drivers: cpuidle: implement DT based idle states infrastructure
From: Ashwin Chaugule @ 2014-07-23 16:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405958786-17243-3-git-send-email-lorenzo.pieralisi@arm.com>

Hi Lorenzo,

On 21 July 2014 12:06, Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> wrote:
> +/**
> + * dt_init_idle_driver() - Parse the DT idle states and initialize the
> + *                        idle driver states array
> + *
> + * @drv:         Pointer to CPU idle driver to be initialized
> + * @start_idx:    First idle state index to be initialized
> + *
> + * On success the states array in the cpuidle driver contains
> + * initialized entries in the states array, starting from index start_idx.
> + *
> + * Return:
> + *     0 on success
> + *     <0 on failure
> + */
> +int dt_init_idle_driver(struct cpuidle_driver *drv, unsigned int start_idx)
> +{
> +       unsigned int i, state_idx = start_idx;
> +       struct cpuidle_state *idle_state;
> +       struct device_node *state_node, *cpu_node;
> +
> +
> +       if (state_idx >= CPUIDLE_STATE_MAX)
> +               return -EINVAL;
> +       /*
> +        * We get the idle states for the first logical cpu in the
> +        * driver mask. The kernel does not check idle states on all
> +        * cpus in the driver mask, they are assumed to be the same
> +        * by default.
> +        */
> +       cpu_node = of_cpu_device_node_get(cpumask_first(drv->cpumask));

Is this an assumption for the short term? My understanding from the
corresponding ACPI discussions is that the order of idle states may
not necessarily be same for all CPUs, even for big.Little?

Cheers,
Ashwin

^ permalink raw reply

* [PATCH v6 6/7] drivers: cpuidle: initialize big.LITTLE driver through DT
From: Catalin Marinas @ 2014-07-23 16:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405958786-17243-7-git-send-email-lorenzo.pieralisi@arm.com>

On Mon, Jul 21, 2014 at 05:06:25PM +0100, Lorenzo Pieralisi wrote:
> With the introduction of DT based idle states, CPUidle drivers for ARM
> can now initialize idle states data through properties in the device tree.
> 
> This patch adds code to the big.LITTLE CPUidle driver to dynamically
> initialize idle states data through the updated device tree source file.
> 
> Cc: Chander Kashyap <chander.kashyap@linaro.org>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

I think for this patch (and the exynos one) we should still allow the
driver to work fine with old DT. Basically if the information is not in
DT, fall back to the original static definitions.

-- 
Catalin

^ permalink raw reply

* [PATCH v6 4/7] arm64: add PSCI CPU_SUSPEND based cpu_suspend support
From: Ashwin Chaugule @ 2014-07-23 16:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405958786-17243-5-git-send-email-lorenzo.pieralisi@arm.com>

On 21 July 2014 12:06, Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> wrote:
> This patch implements the cpu_suspend cpu operations method through
> the PSCI CPU SUSPEND API. The PSCI implementation translates the idle state
> index passed by the cpu_suspend core call into a valid PSCI state according to
> the PSCI states initialized at boot through the cpu_init_idle() CPU
> operations hook.
>
> Entry point is set to cpu_resume physical address, that represents the
> default kernel execution address following a CPU reset; for standby
> states the entry point address is useless and will therefore be ignored
> by the PSCI implementation.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> ---
>  arch/arm64/kernel/psci.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 89 insertions(+)
>
> diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
> index a623c44..bbdf41d 100644
> --- a/arch/arm64/kernel/psci.c
> +++ b/arch/arm64/kernel/psci.c
> @@ -21,6 +21,7 @@
>  #include <linux/reboot.h>
>  #include <linux/pm.h>
>  #include <linux/delay.h>
> +#include <linux/slab.h>
>  #include <uapi/linux/psci.h>
>
>  #include <asm/compiler.h>
> @@ -28,6 +29,7 @@
>  #include <asm/errno.h>
>  #include <asm/psci.h>
>  #include <asm/smp_plat.h>
> +#include <asm/suspend.h>
>  #include <asm/system_misc.h>
>
>  #define PSCI_POWER_STATE_TYPE_STANDBY          0
> @@ -65,6 +67,8 @@ enum psci_function {
>         PSCI_FN_MAX,
>  };
>
> +static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state);
> +
>  static u32 psci_function_id[PSCI_FN_MAX];
>
>  static int psci_to_linux_errno(int errno)
> @@ -93,6 +97,18 @@ static u32 psci_power_state_pack(struct psci_power_state state)
>                  & PSCI_0_2_POWER_STATE_AFFL_MASK);
>  }
>
> +static void psci_power_state_unpack(u32 power_state,
> +                                   struct psci_power_state *state)
> +{
> +       state->id = (power_state & PSCI_0_2_POWER_STATE_ID_MASK) >>
> +                       PSCI_0_2_POWER_STATE_ID_SHIFT;
> +       state->type = (power_state & PSCI_0_2_POWER_STATE_TYPE_MASK) >>
> +                       PSCI_0_2_POWER_STATE_TYPE_SHIFT;
> +       state->affinity_level =
> +                       (power_state & PSCI_0_2_POWER_STATE_AFFL_MASK) >>
> +                       PSCI_0_2_POWER_STATE_AFFL_SHIFT;
> +}
> +
>  /*
>   * The following two functions are invoked via the invoke_psci_fn pointer
>   * and will not be inlined, allowing us to piggyback on the AAPCS.
> @@ -199,6 +215,61 @@ static int psci_migrate_info_type(void)
>         return err;
>  }
>
> +static int cpu_psci_cpu_init_idle(struct device_node *cpu_node,
> +                                 unsigned int cpu)
> +{
> +       int i, ret, count = 0;
> +       struct psci_power_state *psci_states;
> +       struct device_node *state_node;
> +
> +       /*
> +        * If the PSCI cpu_suspend function hook has not been initialized
> +        * idle states must not be enabled, so bail out
> +        */
> +       if (!psci_ops.cpu_suspend)
> +               return -EOPNOTSUPP;
> +
> +       /* Count idle states */
> +       while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
> +                                             count)))
> +               count++;
> +
> +       if (!count)
> +               return -ENODEV;
> +
> +       psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
> +       if (!psci_states) {
> +               pr_warn("idle state psci_state allocation failed\n");
> +               return -ENOMEM;
> +       }
> +
> +       for (i = 0; i < count; i++) {
> +               u32 psci_power_state;
> +
> +               state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
> +
> +               ret = of_property_read_u32(state_node,
> +                                          "arm,psci-suspend-param",
> +                                          &psci_power_state);
> +               if (ret) {
> +                       pr_warn(" * %s missing arm,psci-suspend-param property\n",
> +                               state_node->full_name);
> +                       goto free_mem;
> +               }
> +
> +               pr_debug("psci-power-state %#x index %d\n", psci_power_state,
> +                                                           i);
> +               psci_power_state_unpack(psci_power_state, &psci_states[i]);
> +       }
> +       /* Idle states parsed correctly, initialize per-cpu pointer */
> +       per_cpu(psci_power_state, cpu) = psci_states;
> +       return 0;
> +
> +free_mem:
> +       kfree(psci_states);
> +       return ret;
> +}
> +
>  static int get_set_conduit_method(struct device_node *np)
>  {
>         const char *method;
> @@ -436,8 +507,23 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
>  #endif
>  #endif
>
> +static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
> +{
> +       struct psci_power_state *state = __get_cpu_var(psci_power_state);
> +       /*
> +        * idle state index 0 corresponds to wfi, should never be called
> +        * from the cpu_suspend operations
> +        */
> +       if (WARN_ON_ONCE(!index))
> +               return -EINVAL;
> +
> +       return psci_ops.cpu_suspend(state[index - 1],
> +                                   virt_to_phys(cpu_resume));
> +}
> +
>  const struct cpu_operations cpu_psci_ops = {
>         .name           = "psci",
> +       .cpu_init_idle  = cpu_psci_cpu_init_idle,
>  #ifdef CONFIG_SMP
>         .cpu_init       = cpu_psci_cpu_init,
>         .cpu_prepare    = cpu_psci_cpu_prepare,
> @@ -448,5 +534,8 @@ const struct cpu_operations cpu_psci_ops = {
>         .cpu_kill       = cpu_psci_cpu_kill,
>  #endif
>  #endif
> +#ifdef CONFIG_ARM64_CPU_SUSPEND
> +       .cpu_suspend    = cpu_psci_cpu_suspend,
> +#endif
>  };
>
> --
> 1.9.1

Reviewed-by: Ashwin Chaugule <ashwin.chaugule@linaro.org>

>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [[RFC PATCH]] gpio: gpio-mxc: make sure gpio is input when request IRQ
From: Linus Walleij @ 2014-07-23 16:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140722074257.GC21229@dragon>

On Tue, Jul 22, 2014 at 9:42 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> On Tue, Jul 22, 2014 at 09:19:22AM +0200, Markus Niebel wrote:

>> Currently client drivers have simply interrupts and interrupt-parent
>> in their bindings, but no interrupt-gpios. Therefore in this case a
>> client does not know about a dedicated gpio which is to be requested
>> and configured.
>
> Okay.  I understand your problem now.  This is an issue in case we
> specify a GPIO to be used as interrupt from device tree.  In non-DT
> world, client driver knows this is an interrupt on GPIO, and therefore
> takes the responsibility to request and configure the GPIO to work as
> interrupt.  But in DT case, client driver does not know whether it's an
> IRQ line or GPIO based interrupt.  The consequence is that GPIO
> subsystem, OF subsystem, client driver, none of the three is requesting
> and configuring the GPIO to be used as interrupt.
>
> This is a common issue instead of i.MX specific, and should be addressed
> globally, I think.

This is very well documented in Documentation/gpio/driver.txt these
days. Quoting:

"
It is legal for any IRQ consumer to request an IRQ from any irqchip no matter
if that is a combined GPIO+IRQ driver. The basic premise is that gpio_chip and
irq_chip are orthogonal, and offering their services independent of each
other.

gpiod_to_irq() is just a convenience function to figure out the IRQ for a
certain GPIO line and should not be relied upon to have been called before
the IRQ is used.

So always prepare the hardware and make it ready for action in respective
callbacks from the GPIO and irqchip APIs. Do not rely on gpiod_to_irq() having
been called first.

This orthogonality leads to ambiguities that we need to solve: if there is
competition inside the subsystem which side is using the resource (a certain
GPIO line and register for example) it needs to deny certain operations and
keep track of usage inside of the gpiolib subsystem. This is why the API
below exists.


Locking IRQ usage
-----------------
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
to mark the GPIO as being used as an IRQ:

        int gpiod_lock_as_irq(struct gpio_desc *desc)

This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock
is released:

        void gpiod_unlock_as_irq(struct gpio_desc *desc)

When implementing an irqchip inside a GPIO driver, these two functions should
typically be called in the .startup() and .shutdown() callbacks from the
irqchip.
"

So: make sure each API can be used orthogonally by just poking
into the hardware registers. Do not call gpio_request_one().

Yours,
Linus Walleij

^ permalink raw reply

* [[RFC PATCH]] gpio: gpio-mxc: make sure gpio is input when request IRQ
From: Linus Walleij @ 2014-07-23 16:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405518664-31313-1-git-send-email-list-09_linux_arm@tqsc.de>

On Wed, Jul 16, 2014 at 3:51 PM, Markus Niebel
<list-09_linux_arm@tqsc.de> wrote:

> From: Markus Niebel <Markus.Niebel@tq-group.com>
>
> When requesting an GPIO irq for imx Soc two things are missing:
> - there is no check, if the GPIO is already requested
> - there is no check, if the GPIO is configured as input
>
> The first case can lead to reconfiguring the GPIO pin from third
> party while it is used as IRQ pin, second case will (eventually)
> prevent IRQ from being seen by SOC becaus the pin is driven by
> Soc
>
> This patch tries to implement (logic taken roughly from gpio-omap)
> - basic check if gpio already requested
> - if needed requests the gpio and configures as IN.
> - if gpio is already requested it is only verified if pin is IN
> - gpio is locked as irq
>
> Tested on a not mainlined i.MX6 based hardware with pin configured
> by bootloader as OUT HIGH and expecting a low active IRQ.
>
> Signed-off-by: Markus Niebel <Markus.Niebel@tq-group.com>
> ---
>  drivers/gpio/gpio-mxc.c |   35 +++++++++++++++++++++++++++++++++++
>  1 file changed, 35 insertions(+)
>
> diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
> index db83b3c..4316a38 100644
> --- a/drivers/gpio/gpio-mxc.c
> +++ b/drivers/gpio/gpio-mxc.c
> @@ -175,6 +175,31 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
>         u32 gpio = port->bgc.gc.base + gpio_idx;
>         int edge;
>         void __iomem *reg = port->base;
> +       int ret = 0;
> +
> +       if (!gpiochip_is_requested(&port->bgc.gc, gpio_idx)) {
> +               char label[32];
> +
> +               snprintf(label, 32, "gpio%u-irq", gpio);
> +               ret = gpio_request_one(gpio, GPIOF_DIR_IN, label);

Wut? Auto-request here? This can not be right.

> +       } else {
> +               val = readl(port->base + GPIO_GDIR);
> +               if (val & BIT(gpio_idx))
> +                       ret = -EINVAL;
> +       }
> +
> +       if (ret) {
> +               dev_err(port->bgc.gc.dev, "unable to set gpio_idx %u as IN\n",
> +                       gpio_idx);
> +               return ret;
> +       }
> +
> +       ret = gpio_lock_as_irq(&port->bgc.gc, gpio_idx);

This call should be done in the new
.irq_request_resources callback in struct irq_chip.

> +       if (ret) {
> +               dev_err(port->bgc.gc.dev, "unable to lock gpio_idx %u for IRQ\n",
> +                       gpio_idx);
> +               return ret;
> +       }
>
>         port->both_edges &= ~(1 << gpio_idx);
>         switch (type) {
> @@ -231,6 +256,15 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
>         return 0;
>  }
>
> +static void gpio_irq_shutdown(struct irq_data *d)
> +{
> +       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
> +       struct mxc_gpio_port *port = gc->private;
> +       u32 gpio_idx = d->hwirq;
> +
> +       gpio_unlock_as_irq(&port->bgc.gc, gpio_idx);
> +}

This call should be done in the new
.irq_release_resources callback in struct irq_chip.

Looking at the driver, it should be switched to using the new
irqchip helpers inside gpiolib, see e.g.
commit 7bcbce55f20e41c014df4d5d9c8448f7b5e49d79
"gpio: pca953x: use gpiolib irqchip helpers"

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH v6 2/7] drivers: cpuidle: implement DT based idle states infrastructure
From: Daniel Lezcano @ 2014-07-23 16:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405958786-17243-3-git-send-email-lorenzo.pieralisi@arm.com>

On 07/21/2014 06:06 PM, Lorenzo Pieralisi wrote:
> On most common ARM systems, the low-power states a CPU can be put into are
> not discoverable in HW and require device tree bindings to describe
> power down suspend operations and idle states parameters.
>
> In order to enable DT based idle states and configure idle drivers, this
> patch implements the bulk infrastructure required to parse the device tree
> idle states bindings and initialize the corresponding CPUidle driver states
> data.
>
> The parsing API accepts a start index that defines the first idle state
> that should be initialized by the parsing code in order to give new and
> legacy driver flexibility over which states should be parsed using the
> new DT mechanism.
>
> The idle states list is obtained from the first cpu in the driver
> cpumask, which implicitly means the parsing code expects idle states
> (and related list of phandles) to be the same for all CPUs in the
> CPUidle driver mask. The kernel does not check this assumption, it must
> be enforced by the bootloader to ensure correct system behaviour.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

This patch looks good for me but I have a couple of questions below.

> ---
>   drivers/cpuidle/Kconfig          |   8 +++
>   drivers/cpuidle/Makefile         |   1 +
>   drivers/cpuidle/dt_idle_states.c | 138 +++++++++++++++++++++++++++++++++++++++
>   drivers/cpuidle/dt_idle_states.h |   5 ++
>   4 files changed, 152 insertions(+)
>   create mode 100644 drivers/cpuidle/dt_idle_states.c
>   create mode 100644 drivers/cpuidle/dt_idle_states.h
>
> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
> index 1b96fb9..414e7a96 100644
> --- a/drivers/cpuidle/Kconfig
> +++ b/drivers/cpuidle/Kconfig
> @@ -30,6 +30,14 @@ config CPU_IDLE_GOV_MENU
>   	bool "Menu governor (for tickless system)"
>   	default y
>
> +config DT_IDLE_STATES
> +        bool "Idle states DT support"
> +	depends on ARM || ARM64
> +	help
> +	 Allows the CPU idle framework to initialize CPU idle drivers
> +	 state data by using DT provided nodes compliant with idle states
> +	 device tree bindings.
> +

Wouldn't make sense to make this as an hidden option and let the 
different drivers to set DT_IDLE_STATES if they depend on it ?

>   menu "ARM CPU Idle Drivers"
>   depends on ARM
>   source "drivers/cpuidle/Kconfig.arm"
> diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
> index d8bb1ff..b27a062 100644
> --- a/drivers/cpuidle/Makefile
> +++ b/drivers/cpuidle/Makefile
> @@ -4,6 +4,7 @@
>
>   obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
>   obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
> +obj-$(CONFIG_DT_IDLE_STATES)		  += dt_idle_states.o
>
>   ##################################################################################
>   # ARM SoC drivers
> diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c
> new file mode 100644
> index 0000000..5413132
> --- /dev/null
> +++ b/drivers/cpuidle/dt_idle_states.c
> @@ -0,0 +1,138 @@
> +/*
> + * DT idle states parsing code.
> + *
> + * Copyright (C) 2014 ARM Ltd.
> + * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define pr_fmt(fmt) "DT idle-states: " fmt
> +
> +#include <linux/cpuidle.h>
> +#include <linux/cpumask.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +
> +#include "dt_idle_states.h"
> +
> +static int init_state_node(struct cpuidle_state *idle_state,
> +			   struct device_node *state_node)
> +{
> +	int err;
> +
> +	err = of_property_read_u32(state_node, "wakeup-latency-us",
> +				   &idle_state->exit_latency);
> +	if (err) {
> +		u32 entry_latency, exit_latency;
> +
> +		err = of_property_read_u32(state_node, "entry-latency-us",
> +					   &entry_latency);
> +		if (err) {
> +			pr_debug(" * %s missing entry-latency-us property\n",
> +				 state_node->full_name);
> +			return -EINVAL;
> +		}
> +
> +		err = of_property_read_u32(state_node, "exit-latency-us",
> +					   &exit_latency);
> +		if (err) {
> +			pr_debug(" * %s missing exit-latency-us property\n",
> +				 state_node->full_name);
> +			return -EINVAL;
> +		}
> +		/*
> +		 * If wakeup-latency-us is missing, default to entry+exit
> +		 * latencies as defined in idle states bindings
> +		 */
> +		idle_state->exit_latency = entry_latency + exit_latency;
> +	}
> +
> +	err = of_property_read_u32(state_node, "min-residency-us",
> +				   &idle_state->target_residency);
> +	if (err) {
> +		pr_debug(" * %s missing min-residency-us property\n",
> +			     state_node->full_name);
> +		return -EINVAL;
> +	}
> +
> +	idle_state->flags = CPUIDLE_FLAG_TIME_VALID;
> +	if (of_property_read_bool(state_node, "local-timer-stop"))
> +		idle_state->flags |= CPUIDLE_FLAG_TIMER_STOP;
> +	/*
> +	 * TODO:
> +	 *	replace with kstrdup and pointer assignment when name
> +	 *	and desc become string pointers
> +	 */
> +	strncpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN - 1);
> +	strncpy(idle_state->desc, state_node->name, CPUIDLE_DESC_LEN - 1);
> +	return 0;
> +}
> +
> +/**
> + * dt_init_idle_driver() - Parse the DT idle states and initialize the
> + *			   idle driver states array
> + *
> + * @drv:	  Pointer to CPU idle driver to be initialized
> + * @start_idx:    First idle state index to be initialized
> + *
> + * On success the states array in the cpuidle driver contains
> + * initialized entries in the states array, starting from index start_idx.
> + *
> + * Return:
> + *	0 on success
> + *	<0 on failure
> + */
> +int dt_init_idle_driver(struct cpuidle_driver *drv, unsigned int start_idx)
> +{
> +	unsigned int i, state_idx = start_idx;
> +	struct cpuidle_state *idle_state;
> +	struct device_node *state_node, *cpu_node;
> +
> +
> +	if (state_idx >= CPUIDLE_STATE_MAX)
> +		return -EINVAL;
> +	/*
> +	 * We get the idle states for the first logical cpu in the
> +	 * driver mask. The kernel does not check idle states on all
> +	 * cpus in the driver mask, they are assumed to be the same
> +	 * by default.
> +	 */
> +	cpu_node = of_cpu_device_node_get(cpumask_first(drv->cpumask));
> +
> +	for (i = 0; ; i++) {
> +		int err;
> +
> +		state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
> +		if (!state_node)
> +			break;
> +
> +		if (state_idx == CPUIDLE_STATE_MAX) {
> +			pr_warn("State index reached static CPU idle driver states array size\n");
> +			break;
> +		}
> +
> +		idle_state = &drv->states[state_idx++];
> +		err = init_state_node(idle_state, state_node);
> +		if (err)

As the init_state_node error traces are in pr_debug level, a pr_err 
would help here IMO.

> +			return err;
> +	}
> +
> +	/*
> +	 * If no idle states are detected, return an error and let the idle
> +	 * driver initialization fail accordingly since initializing a driver
> +	 * with simple WFI as an idle state is equivalent to letting the
> +	 * kernel run the default idle loop.
> +	 */
> +	if (!i)
> +		return -ENODATA;
> +
> +	drv->state_count = state_idx;
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(dt_init_idle_driver);
> diff --git a/drivers/cpuidle/dt_idle_states.h b/drivers/cpuidle/dt_idle_states.h
> new file mode 100644
> index 0000000..728c37c
> --- /dev/null
> +++ b/drivers/cpuidle/dt_idle_states.h
> @@ -0,0 +1,5 @@
> +#ifndef __DT_IDLE_STATES
> +#define __DT_IDLE_STATES
> +
> +int dt_init_idle_driver(struct cpuidle_driver *drv, unsigned int start_idx);
> +#endif
>


-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply

* [PATCH] ARM: zynq: DT: Add CAN node
From: Sören Brinkmann @ 2014-07-23 16:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52d799e17cd3539713625c6f6a6666620f52d692.1406120732.git.michal.simek@xilinx.com>

On Wed, 2014-07-23 at 03:05PM +0200, Michal Simek wrote:
> Add node describing Zynq's CAN controller.
> 
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
> 
>  arch/arm/boot/dts/zynq-7000.dtsi | 13 ++++++++++++-
>  1 file changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
> index 366ca6434f54..2287d9b4ed1a 100644
> --- a/arch/arm/boot/dts/zynq-7000.dtsi
> +++ b/arch/arm/boot/dts/zynq-7000.dtsi
> @@ -71,7 +71,18 @@
>  			interrupts = <0 7 4>;
>  			interrupt-parent = <&intc>;
>  			clocks = <&clkc 12>;
> -		};
> +		};
> +
> +		can0: can at e0008000 {
> +			compatible = "xlnx,zynq-can-1.0";
> +			clocks = <&clkc 19>, <&clkc 36>;
> +			clock-names = "can_clk", "pclk";
> +			reg = <0xe0008000 0x1000>;
> +			interrupts = <0 28 4>;
> +			interrupt-parent = <&intc>;
> +			tx-fifo-depth = <0x40>;
> +			rx-fifo-depth = <0x40>;
> +		};

What about the second CAN core? You also probably want to add
'status = "disabled"' in the dtsi.

	S?ren

^ permalink raw reply

* [PATCH v5] pcie: Add Xilinx PCIe Host Bridge IP driver
From: Srikanth Thokala @ 2014-07-23 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

This is the driver for Xilinx AXI PCIe Host Bridge Soft IP

Signed-off-by: Srikanth Thokala <sthokal@xilinx.com>
---
Changes in v5:
- Removed unnecessary checking of port structure.
- Changed the return type of verify_config from int to bool.
- Renamed following functions,
  xilinx_pcie_is_link_up() -> xilinx_pcie_link_is_up()
  xilinx_pcie_verify_config() -> xilinx_pcie_valid_device()
  xilinx_pcie_get_config_base() -> xilinx_pcie_config_base()
- Removed link_up bool flag from port structure, as it is not
  being used.
- Removed unused constants.
- Rebased on 3.16-rc6.
- Fixed some minor comments.
- Thanks Bjorn for the review.

Changes in v4:
- Regarding the comments to separate ECAM functionality,
  I have sent a separate patch and it is decided to implement
  it later. The patch is here,
  https://lkml.org/lkml/2014/5/18/54
- Fixed issue with adding configuration bus resource.
- Moved the logic for setting up bus resources to probe() from
  pcie_setup().
- Instead of mapping all the MSI interrupts in the probe, changed
  to map only when a MSI is requested.
- Earlier, the implementation of legacy and MSI interrupts init-
  is mutually exclusive, now changed to have the legacy interrupts
  init always and MSI interrupt init based on CONFIG_PCI_MSI flag.
- Regarding the MSI generic implementation comment, I will plan to
  do on top of this driver patch.
- Rebased on 3.16-rc2.
- Fixed other minor comments.
- Thanks Arnd and Bjorn for the review.

Changes in v3:
- Rebased on v3.15.0-rc1
- Added support for interrupt-map DT functionality.
- Removed map_irq() wrapper, instead using of_irq_parse_and_map_pci().
- Modified resource mapping logic as per the series
  "PCI: ARM: add support for generic PCI host controller"
- Modified devicetree binding documentation to update with interrupt-
  map properties.
- Use devm calls wherever applicable.
- Fixed minor comments from Jason
- Thanks Jason for the review and suggestions.

Changes in v2:
- Rebased on v3.14.0-rc8
- Removed IP specific DT properties like include-rc, axibar-num etc.,
  as suggested by Jason and Bjorn, Thanks
---
 .../devicetree/bindings/pci/xilinx-pcie.txt        |   62 ++
 drivers/pci/host/Kconfig                           |    7 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-xilinx.c                      |  978 ++++++++++++++++++++
 4 files changed, 1048 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/xilinx-pcie.txt
 create mode 100644 drivers/pci/host/pci-xilinx.c

diff --git a/Documentation/devicetree/bindings/pci/xilinx-pcie.txt b/Documentation/devicetree/bindings/pci/xilinx-pcie.txt
new file mode 100644
index 0000000..3e2c88d
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/xilinx-pcie.txt
@@ -0,0 +1,62 @@
+* Xilinx AXI PCIe Root Port Bridge DT description
+
+Required properties:
+- #address-cells: Address representation for root ports, set to <3>
+- #size-cells: Size representation for root ports, set to <2>
+- #interrupt-cells: specifies the number of cells needed to encode an
+	interrupt source. The value must be 1.
+- compatible: Should contain "xlnx,axi-pcie-host-1.00.a"
+- reg: Should contain AXI PCIe registers location and length
+- device_type: must be "pci"
+- interrupts: Should contain AXI PCIe interrupt
+- interrupt-map-mask,
+  interrupt-map: standard PCI properties to define the mapping of the
+	PCI interface to interrupt numbers.
+- ranges: ranges for the PCI memory regions (I/O space region is not
+	supported by hardware)
+	Please refer to the standard PCI bus binding document for a more
+	detailed explanation
+
+Optional properties:
+- bus-range: PCI bus numbers covered
+
+Interrupt controller child node
++++++++++++++++++++++++++++++++
+Required properties:
+- interrupt-controller: identifies the node as an interrupt controller
+- #address-cells: specifies the number of cells needed to encode an
+	address. The value must be 0.
+- #interrupt-cells: specifies the number of cells needed to encode an
+	interrupt source. The value must be 1.
+
+NOTE:
+The core provides a single interrupt for both INTx/MSI messages. So,
+created a interrupt controller node to support 'interrupt-map' DT
+functionality.  The driver will create an IRQ domain for this map, decode
+the four INTx interrupts in ISR and route them to this domain.
+
+
+Example:
+++++++++
+
+	pci_express: axi-pcie at 50000000 {
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		compatible = "xlnx,axi-pcie-host-1.00.a";
+		reg = < 0x50000000 0x10000000 >;
+		device_type = "pci";
+		interrupts = < 0 52 4 >;
+		interrupt-map-mask = <0 0 0 7>;
+		interrupt-map = <0 0 0 1 &pcie_intc 1>,
+				<0 0 0 2 &pcie_intc 2>,
+				<0 0 0 3 &pcie_intc 3>,
+				<0 0 0 4 &pcie_intc 4>;
+		ranges = < 0x02000000 0 0x60000000 0x60000000 0 0x10000000 >;
+
+		pcie_intc: interrupt-controller {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+		}
+	};
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 21df477..afedcde 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -46,4 +46,11 @@ config PCI_HOST_GENERIC
 	  Say Y here if you want to support a simple generic PCI host
 	  controller, such as the one emulated by kvmtool.
 
+config PCI_XILINX
+	bool "Xilinx AXI PCIe host bridge support"
+	depends on ARCH_ZYNQ
+	help
+	  Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
+	  Host Bridge driver.
+
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 611ba4b..68dfd06 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
 obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
 obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
+obj-$(CONFIG_PCI_XILINX) += pci-xilinx.o
diff --git a/drivers/pci/host/pci-xilinx.c b/drivers/pci/host/pci-xilinx.c
new file mode 100644
index 0000000..5dd9fda
--- /dev/null
+++ b/drivers/pci/host/pci-xilinx.c
@@ -0,0 +1,978 @@
+/*
+ * PCIe host controller driver for Xilinx AXI PCIe Bridge
+ *
+ * Copyright (c) 2012 - 2014 Xilinx, Inc.
+ *
+ * Based on the Tegra PCIe driver
+ *
+ * Bits taken from Synopsys Designware Host controller driver and
+ * ARM PCI Host generic driver.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+/* Register definitions */
+#define XILINX_PCIE_REG_BIR		0x00000130
+#define XILINX_PCIE_REG_IDR		0x00000138
+#define XILINX_PCIE_REG_IMR		0x0000013c
+#define XILINX_PCIE_REG_PSCR		0x00000144
+#define XILINX_PCIE_REG_RPSC		0x00000148
+#define XILINX_PCIE_REG_MSIBASE1	0x0000014c
+#define XILINX_PCIE_REG_MSIBASE2	0x00000150
+#define XILINX_PCIE_REG_RPEFR		0x00000154
+#define XILINX_PCIE_REG_RPIFR1		0x00000158
+#define XILINX_PCIE_REG_RPIFR2		0x0000015c
+
+/* Interrupt registers definitions */
+#define XILINX_PCIE_INTR_LINK_DOWN	BIT(0)
+#define XILINX_PCIE_INTR_ECRC_ERR	BIT(1)
+#define XILINX_PCIE_INTR_STR_ERR	BIT(2)
+#define XILINX_PCIE_INTR_HOT_RESET	BIT(3)
+#define XILINX_PCIE_INTR_CFG_TIMEOUT	BIT(8)
+#define XILINX_PCIE_INTR_CORRECTABLE	BIT(9)
+#define XILINX_PCIE_INTR_NONFATAL	BIT(10)
+#define XILINX_PCIE_INTR_FATAL		BIT(11)
+#define XILINX_PCIE_INTR_INTX		BIT(16)
+#define XILINX_PCIE_INTR_MSI		BIT(17)
+#define XILINX_PCIE_INTR_SLV_UNSUPP	BIT(20)
+#define XILINX_PCIE_INTR_SLV_UNEXP	BIT(21)
+#define XILINX_PCIE_INTR_SLV_COMPL	BIT(22)
+#define XILINX_PCIE_INTR_SLV_ERRP	BIT(23)
+#define XILINX_PCIE_INTR_SLV_CMPABT	BIT(24)
+#define XILINX_PCIE_INTR_SLV_ILLBUR	BIT(25)
+#define XILINX_PCIE_INTR_MST_DECERR	BIT(26)
+#define XILINX_PCIE_INTR_MST_SLVERR	BIT(27)
+#define XILINX_PCIE_INTR_MST_ERRP	BIT(28)
+#define XILINX_PCIE_IMR_ALL_MASK	0x1FF30FED
+#define XILINX_PCIE_IDR_ALL_MASK	0xFFFFFFFF
+
+/* Root Port Error FIFO Read Register definitions */
+#define XILINX_PCIE_RPEFR_ERR_VALID	BIT(18)
+#define XILINX_PCIE_RPEFR_REQ_ID	GENMASK(15, 0)
+#define XILINX_PCIE_RPEFR_ALL_MASK	0xFFFFFFFF
+
+/* Root Port Interrupt FIFO Read Register 1 definitions */
+#define XILINX_PCIE_RPIFR1_INTR_VALID	BIT(31)
+#define XILINX_PCIE_RPIFR1_MSI_INTR	BIT(30)
+#define XILINX_PCIE_RPIFR1_INTR_MASK	GENMASK(28, 27)
+#define XILINX_PCIE_RPIFR1_ALL_MASK	0xFFFFFFFF
+#define XILINX_PCIE_RPIFR1_INTR_SHIFT		27
+
+/* Bridge Info Register definitions */
+#define XILINX_PCIE_BIR_ECAM_SZ_MASK	GENMASK(18, 16)
+#define XILINX_PCIE_BIR_ECAM_SZ_SHIFT	16
+
+/* Root Port Interrupt FIFO Read Register 2 definitions */
+#define XILINX_PCIE_RPIFR2_MSG_DATA	GENMASK(15, 0)
+
+/* Root Port Status/control Register definitions */
+#define XILINX_PCIE_REG_RPSC_BEN	BIT(0)
+
+/* Phy Status/Control Register definitions */
+#define XILINX_PCIE_REG_PSCR_LNKUP	BIT(11)
+
+/* ECAM definitions */
+#define ECAM_BUS_NUM_SHIFT		20
+#define ECAM_DEV_NUM_SHIFT		12
+
+/* Number of MSI IRQs */
+#define XILINX_NUM_MSI_IRQS		128
+
+/* Number of Memory Resources */
+#define XILINX_MAX_NUM_RESOURCES	3
+
+/**
+ * struct xilinx_pcie_port - PCIe port information
+ * @reg_base: IO Mapped Register Base
+ * @irq: Interrupt number
+ * @msi_pages: MSI pages
+ * @root_busno: Root Bus number
+ * @dev: Device pointer
+ * @irq_domain: IRQ domain pointer
+ * @bus_range: Bus range
+ * @resources: Bus Resources
+ */
+struct xilinx_pcie_port {
+	void __iomem *reg_base;
+	u32 irq;
+	unsigned long msi_pages;
+	u8 root_busno;
+	struct device *dev;
+	struct irq_domain *irq_domain;
+	struct resource bus_range;
+	struct list_head resources;
+};
+
+static DECLARE_BITMAP(msi_irq_in_use, XILINX_NUM_MSI_IRQS);
+
+static inline struct xilinx_pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+static inline u32 pcie_read(struct xilinx_pcie_port *port, u32 reg)
+{
+	return readl(port->reg_base + reg);
+}
+
+static inline void pcie_write(struct xilinx_pcie_port *port,
+			      u32 val, u32 reg)
+{
+	writel(val, port->reg_base + reg);
+}
+
+static inline bool xilinx_pcie_link_is_up(struct xilinx_pcie_port *port)
+{
+	return (pcie_read(port, XILINX_PCIE_REG_PSCR) &
+		XILINX_PCIE_REG_PSCR_LNKUP) ? 1 : 0;
+}
+
+/**
+ * xilinx_pcie_clear_err_interrupts - Clear Error Interrupts
+ * @port: PCIe port information
+ */
+static void xilinx_pcie_clear_err_interrupts(struct xilinx_pcie_port *port)
+{
+	u32 val = pcie_read(port, XILINX_PCIE_REG_RPEFR);
+
+	if (val & XILINX_PCIE_RPEFR_ERR_VALID) {
+		dev_dbg(port->dev, "Requester ID %d\n",
+			val & XILINX_PCIE_RPEFR_REQ_ID);
+		pcie_write(port, XILINX_PCIE_RPEFR_ALL_MASK,
+			   XILINX_PCIE_REG_RPEFR);
+	}
+}
+
+/**
+ * xilinx_pcie_valid_device - Check if a valid device is present on bus
+ * @bus: PCI Bus structure
+ * @devfn: device/function
+ *
+ * Return: 'true' on success and 'false' if invalid device is found
+ */
+static bool xilinx_pcie_valid_device(struct pci_bus *bus,
+				     unsigned int devfn)
+{
+	struct xilinx_pcie_port *port = sys_to_pcie(bus->sysdata);
+
+	/* Check if link is up when trying to access downstream ports */
+	if (bus->number != port->root_busno)
+		if (!xilinx_pcie_link_is_up(port))
+			return false;
+
+	/* Only one device down on each root port */
+	if (bus->number == port->root_busno && devfn > 0)
+		return false;
+
+	/*
+	 * Do not read more than one device on the bus directly attached
+	 * to RC.
+	 */
+	if (bus->primary == port->root_busno && devfn > 0)
+		return false;
+
+	return true;
+}
+
+/**
+ * xilinx_pcie_config_base - Get configuration base
+ * @bus: PCI Bus structure
+ * @devfn: Device/function
+ * @where: Offset from base
+ *
+ * Return: Base address of the configuration space needed to be
+ *	   accessed.
+ */
+static void __iomem *xilinx_pcie_config_base(struct pci_bus *bus,
+						 unsigned int devfn,
+						 int where)
+{
+	struct xilinx_pcie_port *port = sys_to_pcie(bus->sysdata);
+	int relbus;
+
+	relbus = (bus->number << ECAM_BUS_NUM_SHIFT) |
+		 (devfn << ECAM_DEV_NUM_SHIFT);
+
+	return port->reg_base + relbus + where;
+}
+
+/**
+ * xilinx_pcie_read_config - Read configuration space
+ * @bus: PCI Bus structure
+ * @devfn: Device/function
+ * @where: Offset from base
+ * @size: Byte/word/dword
+ * @val: Value to be read
+ *
+ * Return: PCIBIOS_SUCCESSFUL on success
+ *	   EINVAL/PCIBIOS_DEVICE_NOT_FOUND/PCIBIOS_BAD_REGISTER_NUMBER
+ *	   on failure.
+ */
+static int xilinx_pcie_read_config(struct pci_bus *bus,
+				   unsigned int devfn, int where,
+				   int size, u32 *val)
+{
+	void __iomem *addr;
+
+	if (!xilinx_pcie_valid_device(bus, devfn)) {
+		*val = 0xFFFFFFFF;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	addr = xilinx_pcie_config_base(bus, devfn, where);
+
+	switch (size) {
+	case 1:
+		*val = readb(addr);
+		break;
+	case 2:
+		*val = readw(addr);
+		break;
+	default:
+		*val = readl(addr);
+		break;
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/**
+ * xilinx_pcie_write_config - Write configuration space
+ * @bus: PCI Bus structure
+ * @devfn: Device/function
+ * @where: Offset from base
+ * @size: Byte/word/dword
+ * @val: Value to be written to device
+ *
+ * Return: PCIBIOS_SUCCESSFUL on success,
+ *	   EINVAL/PCIBIOS_DEVICE_NOT_FOUND/PCIBIOS_BAD_REGISTER_NUMBER
+ *	   on failure.
+ */
+static int xilinx_pcie_write_config(struct pci_bus *bus,
+				    unsigned int devfn, int where,
+				    int size, u32 val)
+{
+	void __iomem *addr;
+
+	if (!xilinx_pcie_valid_device(bus, devfn))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	addr = xilinx_pcie_config_base(bus, devfn, where);
+
+	switch (size) {
+	case 1:
+		writeb(val, addr);
+		break;
+	case 2:
+		writew(val, addr);
+		break;
+	default:
+		writel(val, addr);
+		break;
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/* PCIe operations */
+static struct pci_ops xilinx_pcie_ops = {
+	.read  = xilinx_pcie_read_config,
+	.write = xilinx_pcie_write_config,
+};
+
+/* MSI functions */
+
+/**
+ * xilinx_pcie_destroy_msi - Free MSI number
+ * @irq: IRQ to be freed
+ */
+static void xilinx_pcie_destroy_msi(unsigned int irq)
+{
+	struct irq_desc *desc;
+	struct msi_desc *msi;
+	struct xilinx_pcie_port *port;
+
+	desc = irq_to_desc(irq);
+	msi = irq_desc_get_msi_desc(desc);
+	port = sys_to_pcie(msi->dev->bus->sysdata);
+
+	if (!test_bit(irq, msi_irq_in_use))
+		dev_err(port->dev, "Trying to free unused MSI#%d\n", irq);
+	else
+		clear_bit(irq, msi_irq_in_use);
+}
+
+/**
+ * xilinx_pcie_assign_msi - Allocate MSI number
+ * @port: PCIe port structure
+ *
+ * Return: A valid IRQ on success and error value on failure.
+ */
+static int xilinx_pcie_assign_msi(struct xilinx_pcie_port *port)
+{
+	int pos;
+
+	pos = find_first_zero_bit(msi_irq_in_use, XILINX_NUM_MSI_IRQS);
+	if (pos < XILINX_NUM_MSI_IRQS)
+		set_bit(pos, msi_irq_in_use);
+	else
+		return -ENOSPC;
+
+	return pos;
+}
+
+/**
+ * xilinx_msi_teardown_irq - Destroy the MSI
+ * @chip: MSI Chip descriptor
+ * @irq: MSI IRQ to destroy
+ */
+static void xilinx_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
+{
+	xilinx_pcie_destroy_msi(irq);
+}
+
+/**
+ * xilinx_pcie_msi_setup_irq - Setup MSI request
+ * @chip: MSI chip pointer
+ * @pdev: PCIe device pointer
+ * @desc: MSI descriptor pointer
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int xilinx_pcie_msi_setup_irq(struct msi_chip *chip,
+				     struct pci_dev *pdev,
+				     struct msi_desc *desc)
+{
+	struct xilinx_pcie_port *port = sys_to_pcie(pdev->bus->sysdata);
+	unsigned int irq;
+	int hwirq;
+	struct msi_msg msg;
+	phys_addr_t msg_addr;
+
+	hwirq = xilinx_pcie_assign_msi(port);
+	if (irq < 0)
+		return irq;
+
+	irq = irq_create_mapping(port->irq_domain, hwirq);
+	if (!irq)
+		return -EINVAL;
+
+	irq_set_msi_desc(irq, desc);
+
+	msg_addr = virt_to_phys((void *)port->msi_pages);
+
+	msg.address_hi = 0;
+	msg.address_lo = msg_addr;
+	msg.data = irq;
+
+	write_msi_msg(irq, &msg);
+
+	return 0;
+}
+
+/* MSI Chip Descriptor */
+static struct msi_chip xilinx_pcie_msi_chip = {
+	.setup_irq = xilinx_pcie_msi_setup_irq,
+	.teardown_irq = xilinx_msi_teardown_irq,
+};
+
+/* HW Interrupt Chip Descriptor */
+static struct irq_chip xilinx_msi_irq_chip = {
+	.name = "Xilinx PCIe MSI",
+	.irq_enable = unmask_msi_irq,
+	.irq_disable = mask_msi_irq,
+	.irq_mask = mask_msi_irq,
+	.irq_unmask = unmask_msi_irq,
+};
+
+/**
+ * xilinx_pcie_msi_map - Set the handler for the MSI and mark IRQ as valid
+ * @domain: IRQ domain
+ * @irq: Virtual IRQ number
+ * @hwirq: HW interrupt number
+ *
+ * Return: Always returns 0.
+ */
+static int xilinx_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
+			       irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &xilinx_msi_irq_chip, handle_simple_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+/* IRQ Domain operations */
+static const struct irq_domain_ops msi_domain_ops = {
+	.map = xilinx_pcie_msi_map,
+};
+
+/**
+ * xilinx_pcie_enable_msi - Enable MSI support
+ * @port: PCIe port information
+ */
+static void xilinx_pcie_enable_msi(struct xilinx_pcie_port *port)
+{
+	phys_addr_t msg_addr;
+
+	port->msi_pages = __get_free_pages(GFP_KERNEL, 0);
+	msg_addr = virt_to_phys((void *)port->msi_pages);
+	pcie_write(port, 0x0, XILINX_PCIE_REG_MSIBASE1);
+	pcie_write(port, msg_addr, XILINX_PCIE_REG_MSIBASE2);
+}
+
+/**
+ * xilinx_pcie_add_bus - Add MSI chip info to PCIe bus
+ * @bus: PCIe bus
+ */
+static void xilinx_pcie_add_bus(struct pci_bus *bus)
+{
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		struct xilinx_pcie_port *port = sys_to_pcie(bus->sysdata);
+
+		xilinx_pcie_msi_chip.dev = port->dev;
+		bus->msi = &xilinx_pcie_msi_chip;
+	}
+}
+
+/* INTx Functions */
+
+/**
+ * xilinx_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid
+ * @domain: IRQ domain
+ * @irq: Virtual IRQ number
+ * @hwirq: HW interrupt number
+ *
+ * Return: Always returns 0.
+ */
+static int xilinx_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+				irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+/* INTx IRQ Domain operations */
+static const struct irq_domain_ops intx_domain_ops = {
+	.map = xilinx_pcie_intx_map,
+};
+
+/* PCIe HW Functions */
+
+/**
+ * xilinx_pcie_intr_handler - Interrupt Service Handler
+ * @irq: IRQ number
+ * @data: PCIe port information
+ *
+ * Return: IRQ_HANDLED on success and IRQ_NONE on failure
+ */
+static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data)
+{
+	struct xilinx_pcie_port *port = (struct xilinx_pcie_port *)data;
+	u32 val, mask, status, msi_data;
+
+	/* Read interrupt decode and mask registers */
+	val = pcie_read(port, XILINX_PCIE_REG_IDR);
+	mask = pcie_read(port, XILINX_PCIE_REG_IMR);
+
+	status = val & mask;
+	if (!status)
+		return IRQ_NONE;
+
+	if (status & XILINX_PCIE_INTR_LINK_DOWN)
+		dev_warn(port->dev, "Link Down\n");
+
+	if (status & XILINX_PCIE_INTR_ECRC_ERR)
+		dev_warn(port->dev, "ECRC failed\n");
+
+	if (status & XILINX_PCIE_INTR_STR_ERR)
+		dev_warn(port->dev, "Streaming error\n");
+
+	if (status & XILINX_PCIE_INTR_HOT_RESET)
+		dev_info(port->dev, "Hot reset\n");
+
+	if (status & XILINX_PCIE_INTR_CFG_TIMEOUT)
+		dev_warn(port->dev, "ECAM access timeout\n");
+
+	if (status & XILINX_PCIE_INTR_CORRECTABLE) {
+		dev_warn(port->dev, "Correctable error message\n");
+		xilinx_pcie_clear_err_interrupts(port);
+	}
+
+	if (status & XILINX_PCIE_INTR_NONFATAL) {
+		dev_warn(port->dev, "Non fatal error message\n");
+		xilinx_pcie_clear_err_interrupts(port);
+	}
+
+	if (status & XILINX_PCIE_INTR_FATAL) {
+		dev_warn(port->dev, "Fatal error message\n");
+		xilinx_pcie_clear_err_interrupts(port);
+	}
+
+	if (status & XILINX_PCIE_INTR_INTX) {
+		/* INTx interrupt received */
+		val = pcie_read(port, XILINX_PCIE_REG_RPIFR1);
+
+		/* Check whether interrupt valid */
+		if (!(val & XILINX_PCIE_RPIFR1_INTR_VALID)) {
+			dev_warn(port->dev, "RP Intr FIFO1 read error\n");
+			return IRQ_HANDLED;
+		}
+
+		/* Clear interrupt FIFO register 1 */
+		pcie_write(port, XILINX_PCIE_RPIFR1_ALL_MASK,
+			   XILINX_PCIE_REG_RPIFR1);
+
+		/* Handle INTx Interrupt */
+		val = ((val & XILINX_PCIE_RPIFR1_INTR_MASK) >>
+			XILINX_PCIE_RPIFR1_INTR_SHIFT) + 1;
+		generic_handle_irq(irq_find_mapping(port->irq_domain, val));
+	}
+
+	if (status & XILINX_PCIE_INTR_MSI) {
+		/* MSI Interrupt */
+		val = pcie_read(port, XILINX_PCIE_REG_RPIFR1);
+
+		if (!(val & XILINX_PCIE_RPIFR1_INTR_VALID)) {
+			dev_warn(port->dev, "RP Intr FIFO1 read error\n");
+			return IRQ_HANDLED;
+		}
+
+		if (val & XILINX_PCIE_RPIFR1_MSI_INTR) {
+			msi_data = pcie_read(port, XILINX_PCIE_REG_RPIFR2) &
+				   XILINX_PCIE_RPIFR2_MSG_DATA;
+
+			/* Clear interrupt FIFO register 1 */
+			pcie_write(port, XILINX_PCIE_RPIFR1_ALL_MASK,
+				   XILINX_PCIE_REG_RPIFR1);
+
+			if (IS_ENABLED(CONFIG_PCI_MSI)) {
+				/* Handle MSI Interrupt */
+				generic_handle_irq(msi_data);
+			}
+		}
+	}
+
+	if (status & XILINX_PCIE_INTR_SLV_UNSUPP)
+		dev_warn(port->dev, "Slave unsupported request\n");
+
+	if (status & XILINX_PCIE_INTR_SLV_UNEXP)
+		dev_warn(port->dev, "Slave unexpected completion\n");
+
+	if (status & XILINX_PCIE_INTR_SLV_COMPL)
+		dev_warn(port->dev, "Slave completion timeout\n");
+
+	if (status & XILINX_PCIE_INTR_SLV_ERRP)
+		dev_warn(port->dev, "Slave Error Poison\n");
+
+	if (status & XILINX_PCIE_INTR_SLV_CMPABT)
+		dev_warn(port->dev, "Slave Completer Abort\n");
+
+	if (status & XILINX_PCIE_INTR_SLV_ILLBUR)
+		dev_warn(port->dev, "Slave Illegal Burst\n");
+
+	if (status & XILINX_PCIE_INTR_MST_DECERR)
+		dev_warn(port->dev, "Master decode error\n");
+
+	if (status & XILINX_PCIE_INTR_MST_SLVERR)
+		dev_warn(port->dev, "Master slave error\n");
+
+	if (status & XILINX_PCIE_INTR_MST_ERRP)
+		dev_warn(port->dev, "Master error poison\n");
+
+	/* Clear the Interrupt Decode register */
+	pcie_write(port, status, XILINX_PCIE_REG_IDR);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * xilinx_pcie_free_irq_domain - Free IRQ domain
+ * @port: PCIe port information
+ */
+static void xilinx_pcie_free_irq_domain(struct xilinx_pcie_port *port)
+{
+	int i;
+	u32 irq, num_irqs;
+
+	/* Free IRQ Domain */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+
+		free_pages(port->msi_pages, 0);
+
+		num_irqs = XILINX_NUM_MSI_IRQS;
+	} else {
+		/* INTx */
+		num_irqs = 4;
+	}
+
+	for (i = 0; i < num_irqs; i++) {
+		irq = irq_find_mapping(port->irq_domain, i);
+		if (irq > 0)
+			irq_dispose_mapping(irq);
+	}
+
+	irq_domain_remove(port->irq_domain);
+}
+
+/**
+ * xilinx_pcie_init_irq_domain - Initialize IRQ domain
+ * @port: PCIe port information
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port)
+{
+	struct device *dev = port->dev;
+	struct device_node *node = dev->of_node;
+	struct device_node *pcie_intc_node;
+
+	/* Setup INTx */
+	pcie_intc_node = of_get_next_child(node, NULL);
+	if (!pcie_intc_node) {
+		dev_err(dev, "No PCIe Intc node found\n");
+		return PTR_ERR(pcie_intc_node);
+	}
+
+	port->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
+						 &intx_domain_ops,
+						 port);
+	if (!port->irq_domain) {
+		dev_err(dev, "Failed to get a INTx IRQ domain\n");
+		return PTR_ERR(port->irq_domain);
+	}
+
+	/* Setup MSI */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		port->irq_domain = irq_domain_add_linear(node,
+							 XILINX_NUM_MSI_IRQS,
+							 &msi_domain_ops,
+							 &xilinx_pcie_msi_chip);
+		if (!port->irq_domain) {
+			dev_err(dev, "Failed to get a MSI IRQ domain\n");
+			return PTR_ERR(port->irq_domain);
+		}
+
+		xilinx_pcie_enable_msi(port);
+	}
+
+	return 0;
+}
+
+/**
+ * xilinx_pcie_init_port - Initialize hardware
+ * @port: PCIe port information
+ */
+static void xilinx_pcie_init_port(struct xilinx_pcie_port *port)
+{
+	if (xilinx_pcie_link_is_up(port))
+		dev_info(port->dev, "PCIe Link is UP\n");
+	else
+		dev_info(port->dev, "PCIe Link is DOWN\n");
+
+	/* Disable all interrupts */
+	pcie_write(port, ~XILINX_PCIE_IDR_ALL_MASK,
+		   XILINX_PCIE_REG_IMR);
+
+	/* Clear pending interrupts */
+	pcie_write(port, pcie_read(port, XILINX_PCIE_REG_IDR) &
+			 XILINX_PCIE_IMR_ALL_MASK,
+		   XILINX_PCIE_REG_IDR);
+
+	/* Enable all interrupts */
+	pcie_write(port, XILINX_PCIE_IMR_ALL_MASK, XILINX_PCIE_REG_IMR);
+
+	/* Enable the Bridge enable bit */
+	pcie_write(port, pcie_read(port, XILINX_PCIE_REG_RPSC) |
+			 XILINX_PCIE_REG_RPSC_BEN,
+		   XILINX_PCIE_REG_RPSC);
+}
+
+/**
+ * xilinx_pcie_setup - Setup memory resources
+ * @nr: Bus number
+ * @sys: Per controller structure
+ *
+ * Return: '1' on success and error value on failure
+ */
+static int xilinx_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	struct xilinx_pcie_port *port = sys_to_pcie(sys);
+
+	list_splice_init(&port->resources, &sys->resources);
+
+	return 1;
+}
+
+/**
+ * xilinx_pcie_scan_bus - Scan PCIe bus for devices
+ * @nr: Bus number
+ * @sys: Per controller structure
+ *
+ * Return: Valid Bus pointer on success and NULL on failure
+ */
+static struct pci_bus __init *xilinx_pcie_scan_bus(int nr,
+						   struct pci_sys_data *sys)
+{
+	struct xilinx_pcie_port *port = sys_to_pcie(sys);
+	struct pci_bus *bus;
+
+	port->root_busno = sys->busnr;
+	bus = pci_scan_root_bus(port->dev, sys->busnr, &xilinx_pcie_ops,
+				sys, &sys->resources);
+
+	return bus;
+}
+
+/**
+ * xilinx_pcie_parse_and_add_res - Add resources by parsing ranges
+ * @port: PCIe port information
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port)
+{
+	struct device *dev = port->dev;
+	struct device_node *node = dev->of_node;
+	struct resource *mem;
+	resource_size_t offset;
+	struct of_pci_range_parser parser;
+	struct of_pci_range range;
+	struct pci_host_bridge_window *win;
+	int err = 0, mem_resno = 0;
+
+	/* Get the ranges */
+	if (of_pci_range_parser_init(&parser, node)) {
+		dev_err(dev, "missing \"ranges\" property\n");
+		return -EINVAL;
+	}
+
+	/* Parse the ranges and add the resources found to the list */
+	for_each_of_pci_range(&parser, &range) {
+
+		if (mem_resno >= XILINX_MAX_NUM_RESOURCES) {
+			dev_err(dev, "Maximum memory resources exceeded\n");
+			return -EINVAL;
+		}
+
+		mem = devm_kmalloc(dev, sizeof(*mem), GFP_KERNEL);
+		if (!mem) {
+			err = -ENOMEM;
+			goto free_resources;
+		}
+
+		of_pci_range_to_resource(&range, node, mem);
+
+		switch (mem->flags & IORESOURCE_TYPE_BITS) {
+		case IORESOURCE_MEM:
+			offset = range.cpu_addr - range.pci_addr;
+			mem_resno++;
+			break;
+		default:
+			err = -EINVAL;
+			break;
+		}
+
+		if (err < 0) {
+			dev_warn(dev, "Invalid resource found %pR\n", mem);
+			continue;
+		}
+
+		err = request_resource(&iomem_resource, mem);
+		if (err)
+			goto free_resources;
+
+		pci_add_resource_offset(&port->resources, mem, offset);
+	}
+
+	/* Get the bus range */
+	if (of_pci_parse_bus_range(node, &port->bus_range)) {
+		u32 val = pcie_read(port, XILINX_PCIE_REG_BIR);
+		u8 last;
+
+		last = (val & XILINX_PCIE_BIR_ECAM_SZ_MASK) >>
+			XILINX_PCIE_BIR_ECAM_SZ_SHIFT;
+
+		port->bus_range = (struct resource) {
+			.name	= node->name,
+			.start	= 0,
+			.end	= last,
+			.flags	= IORESOURCE_BUS,
+		};
+	}
+
+	/* Register bus resource */
+	pci_add_resource(&port->resources, &port->bus_range);
+
+	return 0;
+
+free_resources:
+	release_child_resources(&iomem_resource);
+	list_for_each_entry(win, &port->resources, list)
+		devm_kfree(dev, win->res);
+	pci_free_resource_list(&port->resources);
+
+	return err;
+}
+
+/**
+ * xilinx_pcie_parse_dt - Parse Device tree
+ * @port: PCIe port information
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int xilinx_pcie_parse_dt(struct xilinx_pcie_port *port)
+{
+	struct device *dev = port->dev;
+	struct device_node *node = dev->of_node;
+	struct resource regs;
+	const char *type;
+	int err;
+
+	type = of_get_property(node, "device_type", NULL);
+	if (!type || strcmp(type, "pci")) {
+		dev_err(dev, "invalid \"device_type\" %s\n", type);
+		return -EINVAL;
+	}
+
+	err = of_address_to_resource(node, 0, &regs);
+	if (err) {
+		dev_err(dev, "missing \"reg\" property\n");
+		return err;
+	}
+
+	port->reg_base = devm_ioremap_resource(dev, &regs);
+	if (IS_ERR(port->reg_base))
+		return PTR_ERR(port->reg_base);
+
+	port->irq = irq_of_parse_and_map(node, 0);
+	err = devm_request_irq(dev, port->irq, xilinx_pcie_intr_handler,
+			       IRQF_SHARED, "xilinx-pcie", port);
+	if (err) {
+		dev_err(dev, "unable to request irq %d\n", port->irq);
+		return err;
+	}
+
+	return 0;
+}
+
+/**
+ * xilinx_pcie_probe - Probe function
+ * @pdev: Platform device pointer
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int xilinx_pcie_probe(struct platform_device *pdev)
+{
+	struct xilinx_pcie_port *port;
+	struct hw_pci hw;
+	struct device *dev = &pdev->dev;
+	int err;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->dev = dev;
+
+	err = xilinx_pcie_parse_dt(port);
+	if (err) {
+		dev_err(dev, "Parsing DT failed\n");
+		return err;
+	}
+
+	xilinx_pcie_init_port(port);
+
+	err = xilinx_pcie_init_irq_domain(port);
+	if (err) {
+		dev_err(dev, "Failed creating IRQ Domain\n");
+		return err;
+	}
+
+	/*
+	 * Parse PCI ranges, configuration bus range and
+	 * request their resources
+	 */
+	INIT_LIST_HEAD(&port->resources);
+	err = xilinx_pcie_parse_and_add_res(port);
+	if (err) {
+		dev_err(dev, "Failed adding resources\n");
+		return err;
+	}
+
+	platform_set_drvdata(pdev, port);
+
+	/* Register the device */
+	memset(&hw, 0, sizeof(hw));
+	hw = (struct hw_pci) {
+		.nr_controllers	= 1,
+		.private_data	= (void **)&port,
+		.setup		= xilinx_pcie_setup,
+		.map_irq	= of_irq_parse_and_map_pci,
+		.add_bus	= xilinx_pcie_add_bus,
+		.scan		= xilinx_pcie_scan_bus,
+		.ops		= &xilinx_pcie_ops,
+	};
+	pci_common_init_dev(dev, &hw);
+
+	return 0;
+}
+
+/**
+ * xilinx_pcie_remove - Remove function
+ * @pdev: Platform device pointer
+ *
+ * Return: '0' always
+ */
+static int xilinx_pcie_remove(struct platform_device *pdev)
+{
+	struct xilinx_pcie_port *port = platform_get_drvdata(pdev);
+
+	xilinx_pcie_free_irq_domain(port);
+
+	return 0;
+}
+
+static struct of_device_id xilinx_pcie_of_match[] = {
+	{ .compatible = "xlnx,axi-pcie-host-1.00.a", },
+	{}
+};
+
+static struct platform_driver xilinx_pcie_driver = {
+	.driver = {
+		.name = "xilinx-pcie",
+		.owner = THIS_MODULE,
+		.of_match_table = xilinx_pcie_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = xilinx_pcie_probe,
+	.remove = xilinx_pcie_remove,
+};
+module_platform_driver(xilinx_pcie_driver);
+
+MODULE_AUTHOR("Xilinx Inc");
+MODULE_DESCRIPTION("Xilinx AXI PCIe driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 1/6] rtc: sun6i: Add sun6i RTC driver
From: Varka Bhadram @ 2014-07-23 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1406126338-15062-2-git-send-email-wens@csie.org>


On Wednesday 23 July 2014 08:08 PM, Chen-Yu Tsai wrote:
> This patch introduces the driver for the RTC in the Allwinner A31 and
> A23 SoCs.
>
> Unlike the RTC found in A10/A20 SoCs, which was part of the timer, the
> RTC in A31/A23 are a separate hardware block, which also contain a few
> controls for the RTC block hardware (a regulator and RTC block GPIO pin
> latches), while also having separate interrupts for the alarms.
>
> The hardware is different enough to make a different driver for it.
>
(...)

> +Required properties:
> +- compatible : Should be "allwinner,sun6i-a31-rtc"
> +- reg: physical base address of the controller and length of memory mapped
> +  region.
> +- interrupts: IRQ line for the RTC alarm 0.
> +

proper indentation..
- compatible	: Should be "allwinner,sun6i-a31-rtc"
- reg		: physical base address of the controller and length of memory mapped
		  region.
- interrupts	: IRQ line for the RTC alarm 0.
....

> +Example:
> +

(...)

> +
> +	ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq,
> +			0, dev_name(&pdev->dev), chip);

should match open parenthesis...

devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq,
		 0, dev_name(&pdev->dev), chip);

> +	if (ret) {
> +		dev_err(&pdev->dev, "Could not request IRQ\n");
> +		return ret;
> +	}
> +
> +	/* clear the alarm counter value */
> +	writel(0, chip->base + SUN6I_ALRM_COUNTER);
> +
> +	/* disable counter alarm */
> +	writel(0, chip->base + SUN6I_ALRM_EN);
> +
> +	/* disable counter alarm interrupt */
> +	writel(0, chip->base + SUN6I_ALRM_IRQ_EN);
> +
> +	/* disable week alarm */
> +	writel(0, chip->base + SUN6I_ALRM1_EN);
> +
> +	/* disable week alarm interrupt */
> +	writel(0, chip->base + SUN6I_ALRM1_IRQ_EN);
> +
> +	/* clear counter alarm pending interrupts */
> +	writel(SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND, chip->base +
> +			SUN6I_ALRM_IRQ_STA);
> +
> +	/* clear week alarm pending interrupts */
> +	writel(SUN6I_ALRM1_IRQ_STA_WEEK_IRQ_PEND, chip->base +
> +			SUN6I_ALRM1_IRQ_STA);
> +
> +	/* disable alarm wakeup */
> +	writel(0, chip->base + SUN6I_ALARM_CONFIG);
> +
> +	chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev,
> +			&sun6i_rtc_ops, THIS_MODULE);

dto....

> +	if (IS_ERR(chip->rtc)) {
> +		dev_err(&pdev->dev, "unable to register device\n");
> +		return PTR_ERR(chip->rtc);
> +	}
> +
> +	dev_info(&pdev->dev, "RTC enabled\n");
> +
> +	return 0;
> +}
> +
> +static int sun6i_rtc_remove(struct platform_device *pdev)
> +{
> +	struct sun6i_rtc_dev *chip = platform_get_drvdata(pdev);
> +
> +	rtc_device_unregister(chip->rtc);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sun6i_rtc_dt_ids[] = {
> +	{ .compatible = "allwinner,sun6i-a31-rtc" },
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids);
> +
> +static struct platform_driver sun6i_rtc_driver = {
> +	.probe		= sun6i_rtc_probe,
> +	.remove		= sun6i_rtc_remove,
> +	.driver		= {
> +		.name		= "sun6i-rtc",
> +		.owner		= THIS_MODULE,

we can drop owner field....

> +		.of_match_table = sun6i_rtc_dt_ids,
> +	},
> +};
> +
> +module_platform_driver(sun6i_rtc_driver);
> +
> +MODULE_DESCRIPTION("sun6i RTC driver");
> +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
> +MODULE_LICENSE("GPL");

-- 
-Varka Bhadram

^ permalink raw reply

* [PATCH v3 2/2] pwm: rockchip: Added to support for RK3288 SoC
From: Heiko Stübner @ 2014-07-23 16:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1406097521-6457-3-git-send-email-caesar.wang@rock-chips.com>

Hi Caesar.

Am Mittwoch, 23. Juli 2014, 14:38:41 schrieb Caesar Wang:
> This patch added to support the PWM controller found on
> RK3288 SoC.
> 
> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> ---
>  drivers/pwm/pwm-rockchip.c | 141
> +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 122
> insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
> index eec2145..8d72a98 100644
> --- a/drivers/pwm/pwm-rockchip.c
> +++ b/drivers/pwm/pwm-rockchip.c
> @@ -2,6 +2,7 @@
>   * PWM driver for Rockchip SoCs
>   *
>   * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
> + * Copyright (C) 2014 Caesar Wang <caesar.wang@rock-chips.com>

you might want to check who actually holds the copyright for your 
contributions, I guess a "Copyright (C) 2014 Rockchip"-something would be more 
appropriate?


>   *
>   * This program is free software; you can redistribute it and/or
>   * modify it under the terms of the GNU General Public License
> @@ -12,6 +13,7 @@
>  #include <linux/io.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_device.h>
>  #include <linux/platform_device.h>
>  #include <linux/pwm.h>
>  #include <linux/time.h>
> @@ -25,17 +27,89 @@
> 
>  #define PRESCALER		2
> 
> +#define PWM_ENABLE		(1 << 0)
> +#define PWM_CONTINUOUS		(1 << 1)
> +#define PWM_DUTY_POSITIVE	(1 << 3)
> +#define PWM_INACTIVE_NEGATIVE	(0 << 4)
> +#define PWM_OUTPUT_LEFT		(0 << 5)
> +#define PWM_LP_DISABLE		(0 << 8)
> +
>  struct rockchip_pwm_chip {
>  	struct pwm_chip chip;
>  	struct clk *clk;
> +	const struct rockchip_pwm_data *data;
>  	void __iomem *base;
>  };
> 
> +struct rockchip_pwm_regs {
> +	unsigned long duty;
> +	unsigned long period;
> +	unsigned long cntr;
> +	unsigned long ctrl;
> +};
> +
> +struct rockchip_pwm_data {
> +	struct rockchip_pwm_regs regs;
> +	unsigned int prescaler;
> +
> +	void (*set_enable)(struct pwm_chip *chip, bool enable);
> +};
> +
>  static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct
> pwm_chip *c) {
>  	return container_of(c, struct rockchip_pwm_chip, chip);
>  }
> 
> +static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, bool enable)
> +{
> +	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
> +	u32 val = 0;
> +	u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
> +
> +	val = readl_relaxed(pc->base + pc->data->regs.ctrl);
> +
> +	if (enable)
> +		val |= enable_conf;
> +	else
> +		val &= ~enable_conf;
> +
> +	writel_relaxed(val, pc->base + pc->data->regs.ctrl);
> +}
> +
> +static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
> +{
> +	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
> +	u32 val = 0;
> +	u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
> +		PWM_CONTINUOUS | PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
> +
> +	val = readl_relaxed(pc->base + pc->data->regs.ctrl);
> +
> +	if (enable)
> +		val |= enable_conf;
> +	else
> +		val &= ~enable_conf;
> +
> +	writel_relaxed(val, pc->base + pc->data->regs.ctrl);
> +}
> +
> +static void rockchip_pwm_set_enable_vop(struct pwm_chip *chip, bool enable)
> +{
> +	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
> +	u32 val = 0;
> +	u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
> +		PWM_CONTINUOUS | PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
> +
> +	val = readl_relaxed(pc->base + pc->data->regs.ctrl);
> +
> +	if (enable)
> +		val |= enable_conf;
> +	else
> +		val &= ~enable_conf;
> +
> +	writel_relaxed(val, pc->base + pc->data->regs.ctrl);
> +}

not sure if I'm just blind ... do rockchip_pwm_set_enable_v2 and 
rockchip_pwm_set_enable_vop differ at all?

If they don't differ, I guess pwm_data_vop should just use 
rockchip_pwm_set_enable_v2 instead of duplicating it.


Heiko

> +
>  static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device
> *pwm, int duty_ns, int period_ns)
>  {
> @@ -52,20 +126,20 @@ static int rockchip_pwm_config(struct pwm_chip *chip,
> struct pwm_device *pwm, * default prescaler value for all practical clock
> rate values.
>  	 */
>  	div = clk_rate * period_ns;
> -	do_div(div, PRESCALER * NSEC_PER_SEC);
> +	do_div(div, pc->data->prescaler * NSEC_PER_SEC);
>  	period = div;
> 
>  	div = clk_rate * duty_ns;
> -	do_div(div, PRESCALER * NSEC_PER_SEC);
> +	do_div(div, pc->data->prescaler * NSEC_PER_SEC);
>  	duty = div;
> 
>  	ret = clk_enable(pc->clk);
>  	if (ret)
>  		return ret;
> 
> -	writel(period, pc->base + PWM_LRC);
> -	writel(duty, pc->base + PWM_HRC);
> -	writel(0, pc->base + PWM_CNTR);
> +	writel(period, pc->base + pc->data->regs.period);
> +	writel(duty, pc->base + pc->data->regs.duty);
> +	writel(0, pc->base + pc->data->regs.cntr);
> 
>  	clk_disable(pc->clk);
> 
> @@ -76,15 +150,12 @@ static int rockchip_pwm_enable(struct pwm_chip *chip,
> struct pwm_device *pwm) {
>  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
>  	int ret;
> -	u32 val;
> 
>  	ret = clk_enable(pc->clk);
>  	if (ret)
>  		return ret;
> 
> -	val = readl_relaxed(pc->base + PWM_CTRL);
> -	val |= PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
> -	writel_relaxed(val, pc->base + PWM_CTRL);
> +	pc->data->set_enable(chip, true);
> 
>  	return 0;
>  }
> @@ -92,11 +163,8 @@ static int rockchip_pwm_enable(struct pwm_chip *chip,
> struct pwm_device *pwm) static void rockchip_pwm_disable(struct pwm_chip
> *chip, struct pwm_device *pwm) {
>  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
> -	u32 val;
> 
> -	val = readl_relaxed(pc->base + PWM_CTRL);
> -	val &= ~(PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN);
> -	writel_relaxed(val, pc->base + PWM_CTRL);
> +	pc->data->set_enable(chip, false);
> 
>  	clk_disable(pc->clk);
>  }
> @@ -108,12 +176,52 @@ static const struct pwm_ops rockchip_pwm_ops = {
>  	.owner = THIS_MODULE,
>  };
> 
> +static const struct rockchip_pwm_data pwm_data_v1 = {
> +	.regs.duty = PWM_HRC,
> +	.regs.period = PWM_LRC,
> +	.regs.cntr = PWM_CNTR,
> +	.regs.ctrl = PWM_CTRL,
> +	.prescaler = PRESCALER,
> +	.set_enable = rockchip_pwm_set_enable_v1,
> +};
> +
> +static const struct rockchip_pwm_data pwm_data_v2 = {
> +	.regs.duty = PWM_LRC,
> +	.regs.period = PWM_HRC,
> +	.regs.cntr = PWM_CNTR,
> +	.regs.ctrl = PWM_CTRL,
> +	.prescaler = PRESCALER-1,
> +	.set_enable = rockchip_pwm_set_enable_v2,
> +};
> +
> +static const struct rockchip_pwm_data pwm_data_vop = {
> +	.regs.duty = PWM_LRC,
> +	.regs.period = PWM_HRC,
> +	.regs.cntr = PWM_CTRL,
> +	.regs.ctrl = PWM_CNTR,
> +	.prescaler = PRESCALER-1,
> +	.set_enable = rockchip_pwm_set_enable_vop,
> +};
> +
> +static const struct of_device_id rockchip_pwm_dt_ids[] = {
> +	{ .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1},
> +	{ .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2},
> +	{ .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop},
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
> +
>  static int rockchip_pwm_probe(struct platform_device *pdev)
>  {
> +	const struct of_device_id *id;
>  	struct rockchip_pwm_chip *pc;
>  	struct resource *r;
>  	int ret;
> 
> +	id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev);
> +	if (!id)
> +		return -EINVAL;
> +
>  	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
>  	if (!pc)
>  		return -ENOMEM;
> @@ -133,6 +241,7 @@ static int rockchip_pwm_probe(struct platform_device
> *pdev)
> 
>  	platform_set_drvdata(pdev, pc);
> 
> +	pc->data = id->data;
>  	pc->chip.dev = &pdev->dev;
>  	pc->chip.ops = &rockchip_pwm_ops;
>  	pc->chip.base = -1;
> @@ -156,12 +265,6 @@ static int rockchip_pwm_remove(struct platform_device
> *pdev) return pwmchip_remove(&pc->chip);
>  }
> 
> -static const struct of_device_id rockchip_pwm_dt_ids[] = {
> -	{ .compatible = "rockchip,rk2928-pwm" },
> -	{ /* sentinel */ }
> -};
> -MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
> -
>  static struct platform_driver rockchip_pwm_driver = {
>  	.driver = {
>  		.name = "rockchip-pwm",

^ permalink raw reply

* [PATCH 1/2] Added dts defintion for Lenovo ix4-300d nas
From: Benoit Masson @ 2014-07-23 15:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140723141443.GC2856@lunn.ch>

Hi Andrew I've taken your comment into account, yet for the PHY init comment, see my answer below.

Le 23 juil. 2014 ? 16:14, Andrew Lunn <andrew@lunn.ch> a ?crit :
> 
>>> +	/* warning: you need both eth1 & 0 to be initialize for poweroff to shutdown otherwise it reboots */
> 
> What do you mean by initialized? Driver loaded? Interface up? 
Well actually the PHY need to be initialized (at least 1 mII reg written), which from marvel LSP driver always occurs, while it doesn't with mainline PHY driver (drivers/net/phy/marvell.c), so the only simple way I found to have at least one PHY reg on both interface written is to have both eth up at OS config level.

Probably the best option would be to have a reg-init = <reg offset value> on both phy dts definition but the current armada mii doesn't support this dts config...

> 
>> This is a great first version
> 
> I agree with Jason, well done.
> 
Thanks !
>  Andrew

^ permalink raw reply

* [PATCH v6 1/7] Documentation: arm: define DT idle states bindings
From: Daniel Lezcano @ 2014-07-23 15:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405958786-17243-2-git-send-email-lorenzo.pieralisi@arm.com>

On 07/21/2014 06:06 PM, Lorenzo Pieralisi wrote:
> ARM based platforms implement a variety of power management schemes that
> allow processors to enter idle states at run-time.
> The parameters defining these idle states vary on a per-platform basis forcing
> the OS to hardcode the state parameters in platform specific static tables
> whose size grows as the number of platforms supported in the kernel increases
> and hampers device drivers standardization.
>
> Therefore, this patch aims at standardizing idle state device tree bindings
> for ARM platforms. Bindings define idle state parameters inclusive of entry
> methods and state latencies, to allow operating systems to retrieve the
> configuration entries from the device tree and initialize the related power
> management drivers, paving the way for common code in the kernel to deal with
> idle states and removing the need for static data in current and previous
> kernel versions.
>
> ARM64 platforms require the DT to define an entry-method property
> for idle states.
>
> On system implementing PSCI as an enable-method to enter low-power
> states the PSCI CPU suspend method requires the power_state parameter to
> be passed to the PSCI CPU suspend function.
>
> This parameter is specific to a power state and platform specific,
> therefore must be provided by firmware to the OS in order to enable
> proper call sequence.
>
> Thus, this patch also adds a property in the PSCI bindings that
> describes how the PSCI CPU suspend power_state parameter should be
> defined in DT in all device nodes that rely on PSCI CPU suspend method usage.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>



> ---
>   Documentation/devicetree/bindings/arm/cpus.txt     |   8 +
>   .../devicetree/bindings/arm/idle-states.txt        | 679 +++++++++++++++++++++
>   Documentation/devicetree/bindings/arm/psci.txt     |  14 +-
>   3 files changed, 700 insertions(+), 1 deletion(-)
>   create mode 100644 Documentation/devicetree/bindings/arm/idle-states.txt
>
> diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
> index 1fe72a0..a44d4fd 100644
> --- a/Documentation/devicetree/bindings/arm/cpus.txt
> +++ b/Documentation/devicetree/bindings/arm/cpus.txt
> @@ -215,6 +215,12 @@ nodes to be present and contain the properties described below.
>   		Value type: <phandle>
>   		Definition: Specifies the ACC[2] node associated with this CPU.
>
> +	- cpu-idle-states
> +		Usage: Optional
> +		Value type: <prop-encoded-array>
> +		Definition:
> +			# List of phandles to idle state nodes supported
> +			  by this cpu [3].
>
>   Example 1 (dual-cluster big.LITTLE system 32-bit):
>
> @@ -411,3 +417,5 @@ cpus {
>   --
>   [1] arm/msm/qcom,saw2.txt
>   [2] arm/msm/qcom,kpss-acc.txt
> +[3] ARM Linux kernel documentation - idle states bindings
> +    Documentation/devicetree/bindings/arm/idle-states.txt
> diff --git a/Documentation/devicetree/bindings/arm/idle-states.txt b/Documentation/devicetree/bindings/arm/idle-states.txt
> new file mode 100644
> index 0000000..37375c7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/idle-states.txt
> @@ -0,0 +1,679 @@
> +==========================================
> +ARM idle states binding description
> +==========================================
> +
> +==========================================
> +1 - Introduction
> +==========================================
> +
> +ARM systems contain HW capable of managing power consumption dynamically,
> +where cores can be put in different low-power states (ranging from simple
> +wfi to power gating) according to OS PM policies. The CPU states representing
> +the range of dynamic idle states that a processor can enter at run-time, can be
> +specified through device tree bindings representing the parameters required
> +to enter/exit specific idle states on a given processor.
> +
> +According to the Server Base System Architecture document (SBSA, [3]), the
> +power states an ARM CPU can be put into are identified by the following list:
> +
> +- Running
> +- Idle_standby
> +- Idle_retention
> +- Sleep
> +- Off
> +
> +The power states described in the SBSA document define the basic CPU states on
> +top of which ARM platforms implement power management schemes that allow an OS
> +PM implementation to put the processor in different idle states (which include
> +states listed above; "off" state is not an idle state since it does not have
> +wake-up capabilities, hence it is not considered in this document).
> +
> +Idle state parameters (eg entry latency) are platform specific and need to be
> +characterized with bindings that provide the required information to OS PM
> +code so that it can build the required tables and use them at runtime.
> +
> +The device tree binding definition for ARM idle states is the subject of this
> +document.
> +
> +===========================================
> +2 - idle-states definitions
> +===========================================
> +
> +Idle states are characterized for a specific system through a set of
> +timing and energy related properties, that underline the HW behaviour
> +triggered upon idle states entry and exit.
> +
> +The following diagram depicts the CPU execution phases and related timing
> +properties required to enter and exit an idle state:
> +
> +..__[EXEC]__|__[PREP]__|__[ENTRY]__|__[IDLE]__|__[EXIT]__|__[EXEC]__..
> +	    |          |           |          |          |
> +
> +	    |<------ entry ------->|
> +	    |       latency        |
> +					      |<- exit ->|
> +					      |  latency |
> +	    |<-------- min-residency -------->|
> +		       |<-------  wakeup-latency ------->|
> +
> +		Diagram 1: CPU idle state execution phases
> +
> +EXEC:	Normal CPU execution.
> +
> +PREP:	Preparation phase before committing the hardware to idle mode
> +	like cache flushing. This is abortable on pending wake-up
> +	event conditions. The abort latency is assumed to be negligible
> +	(i.e. less than the ENTRY + EXIT duration). If aborted, CPU
> +	goes back to EXEC. This phase is optional. If not abortable,
> +	this should be included in the ENTRY phase instead.
> +
> +ENTRY:	The hardware is committed to idle mode. This period must run
> +	to completion up to IDLE before anything else can happen.
> +
> +IDLE:	This is the actual energy-saving idle period. This may last
> +	between 0 and infinite time, until a wake-up event occurs.
> +
> +EXIT:	Period during which the CPU is brought back to operational
> +	mode (EXEC).
> +
> +entry-latency: Worst case latency required to enter the idle state. The
> +exit-latency may be guaranteed only after entry-latency has passed.
> +
> +min-residency: Minimum period, including preparation and entry, for a given
> +idle state to be worthwhile energywise.
> +
> +wakeup-latency: Maximum delay between the signaling of a wake-up event and the
> +CPU being able to execute normal code again. If not specified, this is assumed
> +to be entry-latency + exit-latency.
> +
> +These timing parameters can be used by an OS in different circumstances.
> +
> +An idle CPU requires the expected min-residency time to select the most
> +appropriate idle state based on the expected expiry time of the next IRQ
> +(ie wake-up) that causes the CPU to return to the EXEC phase.
> +
> +An operating system scheduler may need to compute the shortest wake-up delay
> +for CPUs in the system by detecting how long will it take to get a CPU out
> +of an idle state, eg:
> +
> +wakeup-delay = exit-latency + max(entry-latency - (now - entry-timestamp), 0)
> +
> +In other words, the scheduler can make its scheduling decision by selecting
> +(eg waking-up) the CPU with the shortest wake-up latency.
> +The wake-up latency must take into account the entry latency if that period
> +has not expired. The abortable nature of the PREP period can be ignored
> +if it cannot be relied upon (e.g. the PREP deadline may occur much sooner than
> +the worst case since it depends on the CPU operating conditions, ie caches
> +state).
> +
> +An OS has to reliably probe the wakeup-latency since some devices can enforce
> +latency constraints guarantees to work properly, so the OS has to detect the
> +worst case wake-up latency it can incur if a CPU is allowed to enter an
> +idle state, and possibly to prevent that to guarantee reliable device
> +functioning.
> +
> +The min-residency time parameter deserves further explanation since it is
> +expressed in time units but must factor in energy consumption coefficients.
> +
> +The energy consumption of a cpu when it enters a power state can be roughly
> +characterised by the following graph:
> +
> +               |
> +               |
> +               |
> +           e   |
> +           n   |                                      /---
> +           e   |                               /------
> +           r   |                        /------
> +           g   |                  /-----
> +           y   |           /------
> +               |       ----
> +               |      /|
> +               |     / |
> +               |    /  |
> +               |   /   |
> +               |  /    |
> +               | /     |
> +               |/      |
> +          -----|-------+----------------------------------
> +              0|       1                              time(ms)
> +
> +		Graph 1: Energy vs time example
> +
> +The graph is split in two parts delimited by time 1ms on the X-axis.
> +The graph curve with X-axis values = { x | 0 < x < 1ms } has a steep slope
> +and denotes the energy costs incurred whilst entering and leaving the idle
> +state.
> +The graph curve in the area delimited by X-axis values = {x | x > 1ms } has
> +shallower slope and essentially represents the energy consumption of the idle
> +state.
> +
> +min-residency is defined for a given idle state as the minimum expected
> +residency time for a state (inclusive of preparation and entry) after
> +which choosing that state become the most energy efficient option. A good
> +way to visualise this, is by taking the same graph above and comparing some
> +states energy consumptions plots.
> +
> +For sake of simplicity, let's consider a system with two idle states IDLE1,
> +and IDLE2:
> +
> +          |
> +          |
> +          |
> +          |                                                  /-- IDLE1
> +       e  |                                              /---
> +       n  |                                         /----
> +       e  |                                     /---
> +       r  |                                /-----/--------- IDLE2
> +       g  |                    /-------/---------
> +       y  |        ------------    /---|
> +          |       /           /----    |
> +          |      /        /---         |
> +          |     /    /----             |
> +          |    / /---                  |
> +          |   ---                      |
> +          |  /                         |
> +          | /                          |
> +          |/                           |                  time
> +       ---/----------------------------+------------------------
> +          |IDLE1-energy < IDLE2-energy | IDLE2-energy < IDLE1-energy
> +                                       |
> +                                IDLE2-min-residency
> +
> +		Graph 2: idle states min-residency example
> +
> +In graph 2 above, that takes into account idle states entry/exit energy
> +costs, it is clear that if the idle state residency time (ie time till next
> +wake-up IRQ) is less than IDLE2-min-residency, IDLE1 is the better idle state
> +choice energywise.
> +
> +This is mainly down to the fact that IDLE1 entry/exit energy costs are lower
> +than IDLE2.
> +
> +However, the lower power consumption (ie shallower energy curve slope) of idle
> +state IDLE2 implies that after a suitable time, IDLE2 becomes more energy
> +efficient.
> +
> +The time at which IDLE2 becomes more energy efficient than IDLE1 (and other
> +shallower states in a system with multiple idle states) is defined
> +IDLE2-min-residency and corresponds to the time when energy consumption of
> +IDLE1 and IDLE2 states breaks even.
> +
> +The definitions provided in this section underpin the idle states
> +properties specification that is the subject of the following sections.
> +
> +===========================================
> +3 - idle-states node
> +===========================================
> +
> +ARM processor idle states are defined within the idle-states node, which is
> +a direct child of the cpus node [1] and provides a container where the
> +processor idle states, defined as device tree nodes, are listed.
> +
> +- idle-states node
> +
> +	Usage: Optional - On ARM systems, it is a container of processor idle
> +			  states nodes. If the system does not provide CPU
> +			  power management capabilities or the processor just
> +			  supports idle_standby an idle-states node is not
> +			  required.
> +
> +	Description: idle-states node is a container node, where its
> +		     subnodes describe the CPU idle states.
> +
> +	Node name must be "idle-states".
> +
> +	The idle-states node's parent node must be the cpus node.
> +
> +	The idle-states node's child nodes can be:
> +
> +	- one or more state nodes
> +
> +	Any other configuration is considered invalid.
> +
> +	An idle-states node defines the following properties:
> +
> +	- entry-method
> +		Value type: <stringlist>
> +		Usage and definition depend on ARM architecture version.
> +			# On ARM v8 64-bit this property is required and must
> +			  be one of:
> +			   - "psci" (see bindings in [2])
> +			# On ARM 32-bit systems this property is optional
> +
> +The nodes describing the idle states (state) can only be defined within the
> +idle-states node, any other configuration is considered invalid and therefore
> +must be ignored.
> +
> +===========================================
> +4 - state node
> +===========================================
> +
> +A state node represents an idle state description and must be defined as
> +follows:
> +
> +- state node
> +
> +	Description: must be child of the idle-states node
> +
> +	The state node name shall follow standard device tree naming
> +	rules ([5], 2.2.1 "Node names"), in particular state nodes which
> +	are siblings within a single common parent must be given a unique name.
> +
> +	The idle state entered by executing the wfi instruction (idle_standby
> +	SBSA,[3][4]) is considered standard on all ARM platforms and therefore
> +	must not be listed.
> +
> +	With the definitions provided above, the following list represents
> +	the valid properties for a state node:
> +
> +	- compatible
> +		Usage: Required
> +		Value type: <stringlist>
> +		Definition: Must be "arm,idle-state".
> +
> +	- local-timer-stop
> +		Usage: See definition
> +		Value type: <none>
> +		Definition: if present the CPU local timer control logic is
> +			    lost on state entry, otherwise it is retained.
> +
> +	- entry-latency-us
> +		Usage: Required
> +		Value type: <prop-encoded-array>
> +		Definition: u32 value representing worst case latency in
> +			    microseconds required to enter the idle state.
> +			    The exit-latency-us duration may be guaranteed
> +			    only after entry-latency-us has passed.
> +
> +	- exit-latency-us
> +		Usage: Required
> +		Value type: <prop-encoded-array>
> +		Definition: u32 value representing worst case latency
> +			    in microseconds required to exit the idle state.
> +
> +	- min-residency-us
> +		Usage: Required
> +		Value type: <prop-encoded-array>
> +		Definition: u32 value representing minimum residency duration
> +			    in microseconds, inclusive of preparation and
> +			    entry, for this idle state to be considered
> +			    worthwhile energy wise (refer to section 2 of
> +			    this document for a complete description).
> +
> +	- wakeup-latency-us:
> +		Usage: Optional
> +		Value type: <prop-encoded-array>
> +		Definition: u32 value representing maximum delay between the
> +			    signaling of a wake-up event and the CPU being
> +			    able to execute normal code again. If omitted,
> +			    this is assumed to be equal to:
> +
> +				entry-latency-us + exit-latency-us
> +
> +			    It is important to supply this value on systems
> +			    where the duration of PREP phase (see diagram 1,
> +			    section 2) is non-neglibigle.
> +			    In such systems entry-latency-us + exit-latency-us
> +			    will exceed wakeup-latency-us by this duration.
> +
> +	In addition to the properties listed above, a state node may require
> +	additional properties specifics to the entry-method defined in the
> +	idle-states node, please refer to the entry-method bindings
> +	documentation for properties definitions.
> +
> +===========================================
> +4 - Examples
> +===========================================
> +
> +Example 1 (ARM 64-bit, 16-cpu system, PSCI enable-method):
> +
> +cpus {
> +	#size-cells = <0>;
> +	#address-cells = <2>;
> +
> +	CPU0: cpu at 0 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a57";
> +		reg = <0x0 0x0>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0
> +				   &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU1: cpu at 1 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a57";
> +		reg = <0x0 0x1>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0
> +				   &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU2: cpu at 100 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a57";
> +		reg = <0x0 0x100>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0
> +				   &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU3: cpu at 101 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a57";
> +		reg = <0x0 0x101>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0
> +				   &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU4: cpu at 10000 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a57";
> +		reg = <0x0 0x10000>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0
> +				   &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU5: cpu at 10001 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a57";
> +		reg = <0x0 0x10001>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0
> +				   &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU6: cpu at 10100 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a57";
> +		reg = <0x0 0x10100>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0
> +				   &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU7: cpu at 10101 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a57";
> +		reg = <0x0 0x10101>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0
> +				   &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU8: cpu at 100000000 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a53";
> +		reg = <0x1 0x0>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0
> +				   &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU9: cpu at 100000001 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a53";
> +		reg = <0x1 0x1>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0
> +				   &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU10: cpu at 100000100 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a53";
> +		reg = <0x1 0x100>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0
> +				   &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU11: cpu at 100000101 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a53";
> +		reg = <0x1 0x101>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0
> +				   &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU12: cpu at 100010000 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a53";
> +		reg = <0x1 0x10000>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0
> +				   &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU13: cpu at 100010001 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a53";
> +		reg = <0x1 0x10001>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0
> +				   &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU14: cpu at 100010100 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a53";
> +		reg = <0x1 0x10100>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0
> +				   &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU15: cpu at 100010101 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a53";
> +		reg = <0x1 0x10101>;
> +		enable-method = "psci";
> +		cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0
> +				   &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	idle-states {
> +		entry-method = "arm,psci";
> +
> +		CPU_RETENTION_0_0: cpu-retention-0-0 {
> +			compatible = "arm,idle-state";
> +			arm,psci-suspend-param = <0x0010000>;
> +			entry-latency-us = <20>;
> +			exit-latency-us = <40>;
> +			min-residency-us = <80>;
> +		};
> +
> +		CLUSTER_RETENTION_0: cluster-retention-0 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			arm,psci-suspend-param = <0x1010000>;
> +			entry-latency-us = <50>;
> +			exit-latency-us = <100>;
> +			min-residency-us = <250>;
> +			wakeup-latency-us = <130>;
> +		};
> +
> +		CPU_SLEEP_0_0: cpu-sleep-0-0 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			arm,psci-suspend-param = <0x0010000>;
> +			entry-latency-us = <250>;
> +			exit-latency-us = <500>;
> +			min-residency-us = <950>;
> +		};
> +
> +		CLUSTER_SLEEP_0: cluster-sleep-0 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			arm,psci-suspend-param = <0x1010000>;
> +			entry-latency-us = <600>;
> +			exit-latency-us = <1100>;
> +			min-residency-us = <2700>;
> +			wakeup-latency-us = <1500>;
> +		};
> +
> +		CPU_RETENTION_1_0: cpu-retention-1-0 {
> +			compatible = "arm,idle-state";
> +			arm,psci-suspend-param = <0x0010000>;
> +			entry-latency-us = <20>;
> +			exit-latency-us = <40>;
> +			min-residency-us = <90>;
> +		};
> +
> +		CLUSTER_RETENTION_1: cluster-retention-1 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			arm,psci-suspend-param = <0x1010000>;
> +			entry-latency-us = <50>;
> +			exit-latency-us = <100>;
> +			min-residency-us = <270>;
> +			wakeup-latency-us = <100>;
> +		};
> +
> +		CPU_SLEEP_1_0: cpu-sleep-1-0 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			arm,psci-suspend-param = <0x0010000>;
> +			entry-latency-us = <70>;
> +			exit-latency-us = <100>;
> +			min-residency-us = <300>;
> +			wakeup-latency-us = <150>;
> +		};
> +
> +		CLUSTER_SLEEP_1: cluster-sleep-1 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			arm,psci-suspend-param = <0x1010000>;
> +			entry-latency-us = <500>;
> +			exit-latency-us = <1200>;
> +			min-residency-us = <3500>;
> +			wakeup-latency-us = <1300>;
> +		};
> +	};
> +
> +};
> +
> +Example 2 (ARM 32-bit, 8-cpu system, two clusters):
> +
> +cpus {
> +	#size-cells = <0>;
> +	#address-cells = <1>;
> +
> +	CPU0: cpu at 0 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a15";
> +		reg = <0x0>;
> +		cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU1: cpu at 1 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a15";
> +		reg = <0x1>;
> +		cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU2: cpu at 2 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a15";
> +		reg = <0x2>;
> +		cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU3: cpu at 3 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a15";
> +		reg = <0x3>;
> +		cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>;
> +	};
> +
> +	CPU4: cpu at 100 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a7";
> +		reg = <0x100>;
> +		cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU5: cpu at 101 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a7";
> +		reg = <0x101>;
> +		cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU6: cpu at 102 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a7";
> +		reg = <0x102>;
> +		cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	CPU7: cpu at 103 {
> +		device_type = "cpu";
> +		compatible = "arm,cortex-a7";
> +		reg = <0x103>;
> +		cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>;
> +	};
> +
> +	idle-states {
> +		CPU_SLEEP_0_0: cpu-sleep-0-0 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			entry-latency-us = <200>;
> +			exit-latency-us = <100>;
> +			min-residency-us = <400>;
> +			wakeup-latency-us = <250>;
> +		};
> +
> +		CLUSTER_SLEEP_0: cluster-sleep-0 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			entry-latency-us = <500>;
> +			exit-latency-us = <1500>;
> +			min-residency-us = <2500>;
> +			wakeup-latency-us = <1700>;
> +		};
> +
> +		CPU_SLEEP_1_0: cpu-sleep-1-0 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			entry-latency-us = <300>;
> +			exit-latency-us = <500>;
> +			min-residency-us = <900>;
> +			wakeup-latency-us = <600>;
> +		};
> +
> +		CLUSTER_SLEEP_1: cluster-sleep-1 {
> +			compatible = "arm,idle-state";
> +			local-timer-stop;
> +			entry-latency-us = <800>;
> +			exit-latency-us = <2000>;
> +			min-residency-us = <6500>;
> +			wakeup-latency-us = <2300>;
> +		};
> +	};
> +
> +};
> +
> +===========================================
> +5 - References
> +===========================================
> +
> +[1] ARM Linux Kernel documentation - CPUs bindings
> +    Documentation/devicetree/bindings/arm/cpus.txt
> +
> +[2] ARM Linux Kernel documentation - PSCI bindings
> +    Documentation/devicetree/bindings/arm/psci.txt
> +
> +[3] ARM Server Base System Architecture (SBSA)
> +    http://infocenter.arm.com/help/index.jsp
> +
> +[4] ARM Architecture Reference Manuals
> +    http://infocenter.arm.com/help/index.jsp
> +
> +[5] ePAPR standard
> +    https://www.power.org/documentation/epapr-version-1-1/
> diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt
> index b4a58f3..5aa40ed 100644
> --- a/Documentation/devicetree/bindings/arm/psci.txt
> +++ b/Documentation/devicetree/bindings/arm/psci.txt
> @@ -50,6 +50,16 @@ Main node optional properties:
>
>    - migrate       : Function ID for MIGRATE operation
>
> +Device tree nodes that require usage of PSCI CPU_SUSPEND function (ie idle
> +state nodes, as per bindings in [1]) must specify the following properties:
> +
> +- arm,psci-suspend-param
> +		Usage: Required for state nodes[1] if the corresponding
> +                       idle-states node entry-method property is set
> +                       to "psci".
> +		Value type: <u32>
> +		Definition: power_state parameter to pass to the PSCI
> +			    suspend call.
>
>   Example:
>
> @@ -64,7 +74,6 @@ Case 1: PSCI v0.1 only.
>   		migrate		= <0x95c10003>;
>   	};
>
> -
>   Case 2: PSCI v0.2 only
>
>   	psci {
> @@ -88,3 +97,6 @@ Case 3: PSCI v0.2 and PSCI v0.1.
>
>   		...
>   	};
> +
> +[1] Kernel documentation - ARM idle states bindings
> +    Documentation/devicetree/bindings/arm/idle-states.txt
>


-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply

* [PATCH 3/3] crypto: Add Allwinner Security System crypto accelerator
From: Marek Vasut @ 2014-07-23 15:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140723141309.GA30324@gondor.apana.org.au>

On Wednesday, July 23, 2014 at 04:13:09 PM, Herbert Xu wrote:
> On Wed, Jul 23, 2014 at 04:07:20PM +0200, Marek Vasut wrote:
> > On Wednesday, July 23, 2014 at 03:57:35 PM, Herbert Xu wrote:
> > > On Sat, May 24, 2014 at 02:00:03PM +0200, Marek Vasut wrote:
> > > > > +	}
> > > > > +#endif
> > > > > +
> > > > > +#ifdef CONFIG_CRYPTO_DEV_SUNXI_SS_MD5
> > > > > +	err = crypto_register_shash(&sunxi_md5_alg);
> > > > 
> > > > Do not use shash for such device. This is clearly and ahash (and
> > > > async in general) device. The rule of a thumb here is that you use
> > > > sync algos only for devices which have dedicated instructions for
> > > > computing the transformation. For devices which are attached to some
> > > > kind of bus, you use async algos (ahash etc).
> > > 
> > > I'm sorry that I didn't catch this earlier but there is no such
> > > rule.
> > > 
> > > Unless you need the async interface you should stick to the sync
> > > interfaces for the sake of simplicity.
> > > 
> > > We have a number of existing drivers that are synchronous but
> > > using the async interface.  They should either be converted
> > > over to the sync interface or made interrupt-driven if possible.
> > 
> > Sure, but this device is interrupt driven and uses DMA to feed the crypto
> > engine, therefore async, right ?
> 
> If it's interrupt-driven, then yes it would certainly make sense to
> be async.  But all I see is polling in the latest posting, was the
> first version different?

I stand corrected then, sorry.

Is it possible to use DMA to feed the crypto accelerator, Corentin?

Best regards,
Marek Vasut

^ permalink raw reply

* [PATCH v3 1/3] usb: dwc3: add ST dwc3 glue layer to manage dwc3 HC
From: Lee Jones @ 2014-07-23 15:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1406126915-30601-2-git-send-email-peter.griffin@linaro.org>

On Wed, 23 Jul 2014, Peter Griffin wrote:

> This patch adds the ST glue logic to manage the DWC3 HC
> on STiH407 SoC family. It manages the powerdown signal,
> and configures the internal glue logic and syscfg registers.
> 
> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> ---
>  drivers/usb/dwc3/Kconfig   |   9 ++
>  drivers/usb/dwc3/Makefile  |   1 +
>  drivers/usb/dwc3/dwc3-st.c | 338 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 348 insertions(+)
>  create mode 100644 drivers/usb/dwc3/dwc3-st.c

[...]

> +/*
> + * For all fields in USB2_VBUS_MNGMNT_SEL1
> + * 2?b00 : Override value from Reg 0x30 is selected
> + * 2?b01 : utmiotg_<signal_name> from usb3_top is selected
> + * 2?b10 : pipew_<signal_name> from PIPEW instance is selected
> + * 2?b11 : value is 1'b0
> + */
> +#define REG30	0x0
> +#define UTMIOTG	0x1
> +#define PIPEW	0x2
> +#define ZERO	0x3

Possible register values are usually prefixed with something
descriptive which identifies them.

USB2_VBUS_ looks appropriate here.

[...]

> +/**
> + * struct st_dwc3 - st-dwc3 driver private structure
> + * @dwc3:		platform device pointer
> + * @dev:		device pointer
> + * @glue_base		ioaddr for the glue registers
> + * @regmap		regmap pointer for getting syscfg
> + * @syscfg_reg_off	usb syscfg control offset
> + * @dr_mode		drd static host/device config
> + * @rstc_pwrdn		rest controller for powerdown signal
> + * @rstc_rst		reset controller for softreset signal

Some of these have ':', some of them don't.  I suggest you standardise
to 'all do'.

> + *

Superflous line in comment.

> + */
> +

Superflous '\n'.

Take a look how you did the function headers below.

[...]

> +static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data)
> +{
> +	u32 val;
> +	int err;
> +
> +	err = regmap_read(dwc3_data->regmap, dwc3_data->syscfg_reg_off, &val);
> +	if (err)
> +		return err;
> +
> +	switch (dwc3_data->dr_mode) {
> +	case USB_DR_MODE_PERIPHERAL:
> +		val |= USB_SET_PORT_DEVICE;
> +		dev_dbg(dwc3_data->dev, "Configuring as Device\n");
> +		break;
> +
> +	case USB_DR_MODE_HOST:
> +		val &= USB_HOST_DEFAULT_MASK;
> +		dev_dbg(dwc3_data->dev, "Configuring as Host\n");
> +		break;
> +
> +	default:
> +		dev_err(dwc3_data->dev, "Unsupported mode of operation %d\n"
> +			, dwc3_data->dr_mode);

',' should be on the line above.

> +		return -EINVAL;
> +	}
> +
> +	return regmap_write(dwc3_data->regmap, dwc3_data->syscfg_reg_off, val);
> +}

All of this stuff is pretty minor.

Once fixed apply my Ack on the next revision:

Acked-by: Lee Jones <lee.jones@linaro.org>

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply

* [PATCH 1/2] Added dts defintion for Lenovo ix4-300d nas
From: Sebastian Hesselbarth @ 2014-07-23 15:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140723134534.GF23220@titan.lakedaemon.net>

On 07/23/2014 03:45 PM, Jason Cooper wrote:
> Thanks for the patch!  A few minor things:

Benoit,

I also have some minor remarks just because I stumble over them
all the time.

>> ---
>>   arch/arm/boot/dts/Makefile                     |   1 +
>>   arch/arm/boot/dts/armada-xp-lenovo-ix4300d.dts | 267 +++++++++++++++++++++++++

I looked it up and Lenovo names it "ix4-300d", maybe you should
rename the dts "armada-xp-lenovo-ix4-300d.dts" then.

[...]
>> diff --git a/arch/arm/boot/dts/armada-xp-lenovo-ix4300d.dts b/arch/arm/boot/dts/armada-xp-lenovo-ix4300d.dts
>> new file mode 100644
>> index 0000000..e04e7a6
>> --- /dev/null
>> +++ b/arch/arm/boot/dts/armada-xp-lenovo-ix4300d.dts
>> @@ -0,0 +1,267 @@
>> +/*
>> + * Device Tree file for LENOVO IX4-300d

It is spelled "Lenovo" and the full name is "Lenovo Iomega ix4-300d".
As it is the initial commit, we should be more sensitive on the case
here.

>> + * Copyright (C) 2014, Benoit Masson <yahoo@perenite.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +
>> +/dts-v1/;
>> +
>> +#include <dt-bindings/input/input.h>
>> +#include <dt-bindings/gpio/gpio.h>
>> +#include "armada-xp-mv78230.dtsi"
>> +
>> +/ {
>> +	model = "LENOVO IX4-300d";

Same comment about "Lenovo Iomega ix4-300d"

>> +	compatible = "lenovo,ix4-300d", "marvell,armadaxp-mv78230", "marvell,armadaxp", "marvell,armada-370-xp";
>> +
>> +	chosen {
>> +		bootargs = "console=ttyS0,115200 earlyprintk";

Consider to add

stdout-path = "/soc/internal-regs/serial at 12000";

That way you would not have to fix it up for e.g. Barebox.
Unfortunately, neither Armada 370 nor XP dtsi define node
labels yet, so you have to put the full node path.

>> +	};
>> +
[...]
>> +	soc {
>> +		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000
>> +			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>;
>> +
>> +		pcie-controller {
>> +			status = "okay";
>> +
>> +			pcie at 1,0 {
>> +				/* Port 0, Lane 0 */
>> +				status = "okay";
>> +			};
>> +			pcie at 5,0 {
>> +                                /* Port 1, Lane 0 */
>> +                                status = "okay";
>> +                        };
>> +

Any chance you know what is connected to above PCIe ports?
If so, put a comment above the node itself naming the attached
device, e.g.

/* USB 3.0 xHCI controller */
pcie at 1,0 {...}

Also, I saw you have a good impression about the GPIOs used on
the ix4-300d. If you also know the PERST# GPIOs, add them with

reset-gpios = <&gpioN M GPIO_ACTIVE_LOW>;

where N, M follow gpio# = (32 * N) + M, i.e. N=1, M=22 for gpio54.

>> +		};
>> +
>> +		internal-regs {
>> +			pinctrl {
>> +				poweroff: poweroff {

nit: poweroff_pin: poweroff-pin {...}
like the ones below?

>> +                                        marvell,pins = "mpp24";
>> +                                        marvell,function = "gpio";
>> +                                };
>> +
>> +                                power_button_pin: power-button-pin {
>> +                                        marvell,pins = "mpp44";
>> +                                        marvell,function = "gpio";
>> +                                };
>> +
>> +                                reset_button_pin: reset-button-pin {
>> +                                        marvell,pins = "mpp45";
>> +                                        marvell,function = "gpio";
>> +                                };
>> +				select_button_pin: select-button-pin {
>> +                                        marvell,pins = "mpp41";
>> +                                        marvell,function = "gpio";
>> +                                };
>> +
>> +                                scroll_button_pin: scroll-button-pin {
>> +                                        marvell,pins = "mpp42";
>> +                                        marvell,function = "gpio";
>> +                                };
>> +				hdd_led_pin: hdd-led-pin {
>> +					marvell,pins = "mpp26";
>> +					marvell,function = "gpio";
>> +		                };
[...]
>> +			};
>> +
>> +			serial at 12000 {
>> +				clocks = <&coreclk 0>;

As Andrew already said, no need to duplicate the clocks property.

>> +				status = "okay";
>> +			};
[...]
>> +	spi3 {
>> +                compatible = "spi-gpio";
>> +                status = "okay";
>> +                gpio-sck = <&gpio0 25 0>;
>> +                gpio-mosi = <&gpio1 15 0>; /*gpio 47*/
>> +                cs-gpios = <&gpio0 27 0 >;
[...]
>> +                num-chipselects = <1>;
>> +                #address-cells = <1>;
>> +                #size-cells = <0>;
>> +
>> +                gpio2: gpio2 at 0 {
>> +                        compatible = "fairchild,74hc595";

Freaky we have a driver for a 74x595 8-bit shift register ;)

>> +                        gpio-controller;
>> +                        #gpio-cells = <2>;
>> +                        reg = <0>;
>> +                        registers-number = <2>;
>> +                        spi-max-frequency = <100000>;
>> +                };
>> +	};
>> +
>> +	gpio-leds {
>> +                compatible = "gpio-leds";
>> +		pinctrl-0 = <&hdd_led_pin>;
>> +		pinctrl-names = "default";
>> +
>> +		hdd-led {
>> +                        label = "ix4300d:blue:hdd";

Can you get rid of "ix4300d:" or rename it to "ix4-300d:" without
breaking any userspace stuff? If so, please update all LEDs.

>> +                        gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
>> +                        default-state = "off";
>> +                };
[...]
>> +	/* warning: you need both eth1 & 0 to be initialize for poweroff to shutdown otherwise it reboots */

I don't get the comment.

> This is a great first version

Yup, Thanks!

Sebastian

^ permalink raw reply

* [PATCH v5 0/3] arm64: Add seccomp support
From: Kees Cook @ 2014-07-23 15:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <53CF5F9E.4020404@linaro.org>

On Wed, Jul 23, 2014 at 12:09 AM, AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:
> On 07/23/2014 05:16 AM, Kees Cook wrote:
>>
>> On Tue, Jul 22, 2014 at 2:14 AM, AKASHI Takahiro
>> <takahiro.akashi@linaro.org> wrote:
>>>
>>> (Please apply this patch after my audit patch in order to avoid some
>>> conflict on arm64/Kconfig.)
>>>
>>> This patch enables secure computing (system call filtering) on arm64.
>>> System calls can be allowed or denied by loaded bpf-style rules.
>>> Architecture specific part is to run secure_computing() on syscall entry
>>> and check the result. See [3/3]
>>
>>
>> Thanks for working on this!
>>
>>> Prerequisites are:
>>>   * "arm64: Add audit support" patch
>>>
>>> This code is tested on ARMv8 fast model using
>>>   * libseccomp v2.1.1 with modifications for arm64 and verified by its
>>> "live"
>>>     tests, 20, 21 and 24.
>>>   * modified version of Kees' seccomp test for 'changing/skipping a
>>> syscall'
>>>     behavior
>>
>>
>> Would you be able to share this? I'd love to add it to the seccomp
>> regression suite for the arm64-specific parts.
>
>
> Yep, I forked your repo here:
> https://github.com/t-akashi/seccomp.git
> (See trace_arm64 branch)

Great, thanks! I'll incorporate your changes into my trace branch. (It
looks like using PTRACE_GETREGSET works on all archs, so I'll switch
to using that for all.)

-Kees

>
> Thanks,
> -Takahiro AKASHI
>
>
>> Thanks!
>>
>> -Kees
>>
>>>
>>> Changes v4 -> v5:
>>> * rebased to v3.16-rc
>>> * add patch [1/3] to allow ptrace to change a system call
>>>    (please note that this patch should be applied even without seccomp.)
>>>
>>> Changes v3 -> v4:
>>> * removed the following patch and moved it to "arm64: prerequisites for
>>>    audit and ftrace" patchset since it is required for audit and ftrace
>>> in
>>>    case of !COMPAT, too.
>>>    "arm64: is_compat_task is defined both in asm/compat.h and
>>> linux/compat.h"
>>>
>>> Changes v2 -> v3:
>>> * removed unnecessary 'type cast' operations [2/3]
>>> * check for a return value (-1) of secure_computing() explicitly [2/3]
>>> * aligned with the patch, "arm64: split syscall_trace() into separate
>>>    functions for enter/exit" [2/3]
>>> * changed default of CONFIG_SECCOMP to n [2/3]
>>>
>>> Changes v1 -> v2:
>>> * added generic seccomp.h for arm64 to utilize it [1,2/3]
>>> * changed syscall_trace() to return more meaningful value (-EPERM)
>>>    on seccomp failure case [2/3]
>>> * aligned with the change in "arm64: make a single hook to
>>> syscall_trace()
>>>    for all syscall features" v2 [2/3]
>>> * removed is_compat_task() definition from compat.h [3/3]
>>>
>>> AKASHI Takahiro (3):
>>>    arm64: ptrace: reload a syscall number after ptrace operations
>>>    asm-generic: Add generic seccomp.h for secure computing mode 1
>>>    arm64: Add seccomp support
>>>
>>>   arch/arm64/Kconfig               |   14 ++++++++++++++
>>>   arch/arm64/include/asm/seccomp.h |   25 +++++++++++++++++++++++++
>>>   arch/arm64/include/asm/unistd.h  |    3 +++
>>>   arch/arm64/kernel/entry.S        |    2 ++
>>>   arch/arm64/kernel/ptrace.c       |   18 ++++++++++++++++++
>>>   include/asm-generic/seccomp.h    |   28 ++++++++++++++++++++++++++++
>>>   6 files changed, 90 insertions(+)
>>>   create mode 100644 arch/arm64/include/asm/seccomp.h
>>>   create mode 100644 include/asm-generic/seccomp.h
>>>
>>> --
>>> 1.7.9.5
>>>
>>
>>
>>
>



-- 
Kees Cook
Chrome OS Security

^ permalink raw reply

* [PATCH v3 2/3] usb: dwc3: dwc3-st: Add st-dwc3 devicetree bindings documentation
From: Lee Jones @ 2014-07-23 15:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1406126915-30601-3-git-send-email-peter.griffin@linaro.org>

On Wed, 23 Jul 2014, Peter Griffin wrote:

> This patch documents the device tree documentation required for
> the ST usb3 controller glue layer found in STiH407 devices.
> 
> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> ---
>  Documentation/devicetree/bindings/usb/dwc3-st.txt | 69 +++++++++++++++++++++++
>  1 file changed, 69 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/usb/dwc3-st.txt
> 
> diff --git a/Documentation/devicetree/bindings/usb/dwc3-st.txt b/Documentation/devicetree/bindings/usb/dwc3-st.txt
> new file mode 100644
> index 0000000..de3fea3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/dwc3-st.txt
> @@ -0,0 +1,69 @@
> +ST DWC3 glue logic
> +
> +This file documents the parameters for the dwc3-st driver.
> +This driver controls the glue logic used to configure the dwc3 core on
> +STiH407 based platforms.
> +
> +Required properties:
> + - compatible	: must be "st,stih407-dwc3"

Does this only exist for Cannes?

> + - reg		: glue logic base address and USB syscfg ctrl register offset
> + - reg-names	: should be "reg-glue" and "syscfg-reg"
> + - st,syscon	: should be phandle to system configuration node which
> +		  encompasses the glue registers

This should be st,syscfg.  As you have it in the example.

Besides this small issue, I don't see anything controversial so once
fixed up, you can apply my:

Acked-by: Lee Jones <lee.jones@linaro.org>

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply

* [PATCH v5 2/2] serial: 8250_dw: Add support for deferred probing
From: Chen-Yu Tsai @ 2014-07-23 15:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1406129587-24668-1-git-send-email-wens@csie.org>

The 8250_dw driver fails to probe if the specified clock isn't
registered at probe time. Even if a clock frequency is given,
the required clock might be gated because it wasn't properly
enabled.

This happened to me when the device is registered through DT,
and the clock was part of an MFD, the PRCM found on A31 and A23
SoCs. Unlike core clocks that are registered with OF_CLK_DECLARE,
which happen almost immediately after the kernel starts, the
clocks are registered as sub-devices of the PRCM MFD platform
device. Even though devices are registered in the order they are
found in the DT, the drivers are registered in a different,
arbitrary order. It is possible that the 8250_dw driver is
registered, and thus associated with the device and probed, before
the clock driver is registered and probed.

8250_dw then reports unable to get the clock, and fails. Without
a working console, the kernel panics.

This patch adds support for deferred probe handling for the clock
and reset controller. It also fixes the cleanup path if
serial8250_register_8250_port fails.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 drivers/tty/serial/8250/8250_dw.c | 41 ++++++++++++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 501db2f..4db7987 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -365,8 +365,10 @@ static int dw8250_probe(struct platform_device *pdev)
 
 	data->usr_reg = DW_UART_USR;
 	data->clk = devm_clk_get(&pdev->dev, "baudclk");
-	if (IS_ERR(data->clk))
+	if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
 		data->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
 	if (!IS_ERR(data->clk)) {
 		err = clk_prepare_enable(data->clk);
 		if (err)
@@ -377,15 +379,23 @@ static int dw8250_probe(struct platform_device *pdev)
 	}
 
 	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
+	if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
+		err = -EPROBE_DEFER;
+		goto err_clk;
+	}
 	if (!IS_ERR(data->pclk)) {
 		err = clk_prepare_enable(data->pclk);
 		if (err) {
 			dev_err(&pdev->dev, "could not enable apb_pclk\n");
-			return err;
+			goto err_clk;
 		}
 	}
 
 	data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
+	if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
+		err = -EPROBE_DEFER;
+		goto err_pclk;
+	}
 	if (!IS_ERR(data->rst))
 		reset_control_deassert(data->rst);
 
@@ -403,18 +413,21 @@ static int dw8250_probe(struct platform_device *pdev)
 	if (pdev->dev.of_node) {
 		err = dw8250_probe_of(&uart.port, data);
 		if (err)
-			return err;
+			goto err_reset;
 	} else if (ACPI_HANDLE(&pdev->dev)) {
 		err = dw8250_probe_acpi(&uart, data);
 		if (err)
-			return err;
+			goto err_reset;
 	} else {
-		return -ENODEV;
+		err = -ENODEV;
+		goto err_reset;
 	}
 
 	data->line = serial8250_register_8250_port(&uart);
-	if (data->line < 0)
-		return data->line;
+	if (data->line < 0) {
+		err = data->line;
+		goto err_reset;
+	}
 
 	platform_set_drvdata(pdev, data);
 
@@ -422,6 +435,20 @@ static int dw8250_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 
 	return 0;
+
+err_reset:
+	if (!IS_ERR(data->rst))
+		reset_control_assert(data->rst);
+
+err_pclk:
+	if (!IS_ERR(data->pclk))
+		clk_disable_unprepare(data->pclk);
+
+err_clk:
+	if (!IS_ERR(data->clk))
+		clk_disable_unprepare(data->clk);
+
+	return err;
 }
 
 static int dw8250_remove(struct platform_device *pdev)
-- 
2.0.1

^ permalink raw reply related

* [PATCH v5 1/2] serial: 8250_dw: Add optional reset control support
From: Chen-Yu Tsai @ 2014-07-23 15:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1406129587-24668-1-git-send-email-wens@csie.org>

The Allwinner A31 and A23 SoCs have a reset controller
maintaining the UART in reset by default.

This patch adds optional reset support to the driver.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt | 1 +
 drivers/tty/serial/8250/8250_dw.c                             | 9 +++++++++
 2 files changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
index 095ac71..7f76214 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
@@ -15,6 +15,7 @@ The supplying peripheral clock can also be handled, needing a second property
 	Required elements: "baudclk", "apb_pclk"
 
 Optional properties:
+- resets : phandle to the parent reset controller.
 - reg-shift : quantity to shift the register offsets by.  If this property is
   not present then the register offsets are not shifted.
 - reg-io-width : the size (in bytes) of the IO accesses that should be
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index affdcb1..501db2f 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/clk.h>
+#include <linux/reset.h>
 #include <linux/pm_runtime.h>
 
 #include <asm/byteorder.h>
@@ -60,6 +61,7 @@ struct dw8250_data {
 	int			line;
 	struct clk		*clk;
 	struct clk		*pclk;
+	struct reset_control	*rst;
 	struct uart_8250_dma	dma;
 };
 
@@ -383,6 +385,10 @@ static int dw8250_probe(struct platform_device *pdev)
 		}
 	}
 
+	data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
+	if (!IS_ERR(data->rst))
+		reset_control_deassert(data->rst);
+
 	data->dma.rx_chan_id = -1;
 	data->dma.tx_chan_id = -1;
 	data->dma.rx_param = data;
@@ -426,6 +432,9 @@ static int dw8250_remove(struct platform_device *pdev)
 
 	serial8250_unregister_port(data->line);
 
+	if (!IS_ERR(data->rst))
+		reset_control_assert(data->rst);
+
 	if (!IS_ERR(data->pclk))
 		clk_disable_unprepare(data->pclk);
 
-- 
2.0.1

^ permalink raw reply related

* [PATCH v5 0/2] serial: 8250_dw: optional reset control and deferred probe support
From: Chen-Yu Tsai @ 2014-07-23 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Greg,

This series adds optional reset control and deferred probing support
to 8250_dw. These are required to support the UARTs on sun6i/sun8i.
They were originally part of my sun8i PRCM series. The other parts
of that series have been merged already. It would be really nice
if we could get these 2 in as well.

Patch 1 adds optional reset control support to the 8250_dw, which
is used by sun6i and sun8i platforms. Till now, this wasn't needed
from a working standpoint, as the bootloader de-asserts the reset
control on the console UART for us. However, during the development
of the sun8i patches, I noticed other UARTs wouldn't work. Also the
new sun6i A31 Hummingbird has multiple UARTs available, which would
require this patch.

Patch 2 adds deferred probing to 8250_dw. In my case, even though
the clocks and reset controller "devices" were registered before
the UART, the 8250_dw driver binded with the UART devices before
the clocks and resets were available. This resulted in the 8250_dw
driver failing. I only tested the R_UART device.

Patch 2 also does proper cleanup in the event that probing failed.

Maxime, I dropped your Acked-by because I added the cleanup code
path.

Changes since v4:
  - Rebased onto tty-next (4847914)
  - Do proper cleanup in the probe function if errors are encountered.

No changes before v4.


Cheers
ChenYu


Chen-Yu Tsai (2):
  serial: 8250_dw: Add optional reset control support
  serial: 8250_dw: Add support for deferred probing

 .../bindings/serial/snps-dw-apb-uart.txt           |  1 +
 drivers/tty/serial/8250/8250_dw.c                  | 50 +++++++++++++++++++---
 2 files changed, 44 insertions(+), 7 deletions(-)

-- 
2.0.1

^ permalink raw reply

* [PATCH v3 3/3] MAINTAINERS: Add dwc3-st.c file to ARCH/STI architecture
From: Lee Jones @ 2014-07-23 15:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1406126915-30601-4-git-send-email-peter.griffin@linaro.org>

On Wed, 23 Jul 2014, Peter Griffin wrote:

> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)

Acked-by: Lee Jones <lee.jones@linaro.org>
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 702ca10..269ad3b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1325,6 +1325,7 @@ F:	drivers/pinctrl/pinctrl-st.c
>  F:	drivers/media/rc/st_rc.c
>  F:	drivers/i2c/busses/i2c-st.c
>  F:	drivers/tty/serial/st-asc.c
> +F:	drivers/usb/dwc3/dwc3-st.c
>  
>  ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
>  M:	Lennert Buytenhek <kernel@wantstofly.org>

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply

* [PATCH v7 0/5] Add Keystone PCIe controller driver
From: Murali Karicheri @ 2014-07-23 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140722225708.GB27965@google.com>


Bjorn,

On 07/22/2014 06:57 PM, Bjorn Helgaas wrote:
> On Mon, Jul 21, 2014 at 12:58:40PM -0400, Murali Karicheri wrote:

>> Murali Karicheri (5):
>>    PCI: designware: add rd[wr]_other_conf API
>>    PCI: designware: refactor MSI code to work with v3.65 dw hardware
>
> I applied the above two to my pci/host-designware branch.  The rest didn't
> apply cleanly because I applied Kishon's DRA7xx changes first, and there
> are several conflicts.  Can you rebase the rest of them on top of
> pci/host-designware?

Thanks for applying 1 and 2.

I will fix up 3 based on your branch and send you updated patch 3 and 4 
today.  Hope you can apply this updated patch so that I don't have to 
address any rebase issues. Regarding the MRSS comment, I will discuss it 
on that thread and send you a fix for removing the bootargs depedency 
based on what comes out of that discussion. Is that fine?

Regards,

Murali

>
>>    PCI: designware: enhance dw_pcie_host_init() to support v3.65 DW
>>      hardware
>>    PCI: add PCI controller for keystone PCIe h/w
>>    PCI: keystone: Update maintainer information
>
> You can squash the MAINTAINERS update into the driver addition.  They're
> logically part of the same change.
>
> Bjorn
>
>>   .../devicetree/bindings/pci/pci-keystone.txt       |   68 +++
>>   MAINTAINERS                                        |    7 +
>>   drivers/pci/host/Kconfig                           |    5 +
>>   drivers/pci/host/Makefile                          |    1 +
>>   drivers/pci/host/pci-keystone-dw.c                 |  521 ++++++++++++++++++++
>>   drivers/pci/host/pci-keystone.c                    |  386 +++++++++++++++
>>   drivers/pci/host/pci-keystone.h                    |   58 +++
>>   drivers/pci/host/pcie-designware.c                 |  116 +++--
>>   drivers/pci/host/pcie-designware.h                 |    9 +
>>   9 files changed, 1135 insertions(+), 36 deletions(-)
>>   create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
>>   create mode 100644 drivers/pci/host/pci-keystone-dw.c
>>   create mode 100644 drivers/pci/host/pci-keystone.c
>>   create mode 100644 drivers/pci/host/pci-keystone.h
>>
>> --
>> 1.7.9.5
>>

^ permalink raw reply

* [alsa-devel] [PATCH 2/4] ASoC: s3c64xx/smartq: use dynamic registration
From: Linus Walleij @ 2014-07-23 15:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140716110927.GK7978@ulmo>

On Wed, Jul 16, 2014 at 1:09 PM, Thierry Reding
<thierry.reding@gmail.com> wrote:
> On Wed, Jul 16, 2014 at 09:50:02AM +0100, Rob Jones wrote:

>> In light of this, should I hold off starting on devm_gpiod_get_array()
>> as discussed on here last week?
>
> I'll let Alex or Linus answer this, since I wasn't involved in the
> devm_gpiod_get_array() discussions.

I'm gonna shut up in this thread as Alex is doing such an excellent
job at hashing out the details of gpiod*, and he understands it way
better than me.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCHv2 06/10] ARM: DRA7: hwmod_data: Add mailbox hwmod data
From: Suman Anna @ 2014-07-23 15:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140723092449.GF22006@atomide.com>

On 07/23/2014 04:24 AM, Tony Lindgren wrote:
> * Tony Lindgren <tony@atomide.com> [140716 00:10]:
>> * Suman Anna <s-anna@ti.com> [140715 09:59]:
>>> Hi Tony,
>>>
>>> On 07/15/2014 08:30 AM, Tony Lindgren wrote:
>>>> * Suman Anna <s-anna@ti.com> [140711 14:47]:
>>>>> Add the hwmod data for the 13 instances of the system mailbox
>>>>> IP in DRA7 SoC. The patch is needed for performing a soft-reset
>>>>> while configuring the respective mailbox instance, otherwise is
>>>>> a non-essential change for functionality. The modules are smart
>>>>> idled on reset, and the IP module mode is hardware controlled.
>>>>>
>>>>> Cc: Rajendra Nayak <rnayak@ti.com>
>>>>> Cc: Paul Walmsley <paul@pwsan.com>
>>>>> Signed-off-by: Suman Anna <s-anna@ti.com>
>>>>> ---
>>>>>  arch/arm/mach-omap2/omap_hwmod_7xx_data.c | 305 ++++++++++++++++++++++++++++++
>>>>>  1 file changed, 305 insertions(+)
>>>>>
>>>>> diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
>>>>> index 20b4398..e35f5b1 100644
>>>>> --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
>>>>> +++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
>>>>> @@ -939,6 +939,194 @@ static struct omap_hwmod dra7xx_i2c5_hwmod = {
>>>>>  };
>>>>>  
>>>>>  /*
>>>>> + * 'mailbox' class
>>>>> + *
>>>>> + */
>>>>> +
>>>>> +static struct omap_hwmod_class_sysconfig dra7xx_mailbox_sysc = {
>>>>> +	.rev_offs	= 0x0000,
>>>>> +	.sysc_offs	= 0x0010,
>>>>> +	.sysc_flags	= (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
>>>>> +			   SYSC_HAS_SOFTRESET),
>>>>> +	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
>>>>> +	.sysc_fields	= &omap_hwmod_sysc_type2,
>>>>> +};
>>>>> +
>>>>> +static struct omap_hwmod_class dra7xx_mailbox_hwmod_class = {
>>>>> +	.name	= "mailbox",
>>>>> +	.sysc	= &dra7xx_mailbox_sysc,
>>>>> +};
>>>>
>>>> Hmm I'm seeing just the following MAILBOX_SYSCONFIG in at least
>>>> am57xx TRM:
>>>>
>>>> 31:4	RESERVED
>>>> 3:2	SIDLEMODE	0 = force-idle 1 = no-idle, 2 = smart-idle, 3 = reserved
>>>> 1	RESERVED
>>>> 0	SOFTRESET
>>>>
>>>> So it seems that SYSC_HAS_RESET_STATUS above is wrong? Can you guys
>>>> please check.
>>>
>>> The same SOFTRESET bit is used for both triggering the softreset and
>>> reading the reset done status. Once you write a 1 to trigger a reset,
>>> the bit will be cleared once the reset is done. This is no different
>>> from OMAP4. The logic in _wait_softreset_complete in omap_hwmod.c was
>>> already designed to work with this properly.
>>
>> Oh OK, I guess I got it confused with SYSS_HAS_RESET_STATUS. Paul,
>> want to ack this one if no other issues? I can then set this series
>> into a branch against -rc1 that we can all merge in as needed as
>> it seems that the driver changes may need this branch as a base too.
> 
> I have applied these into omap-for-v3.17/mailbox and merged also
> into omap-for-v3.17/soc.
> 

Thank you, Tony.

regards
Suman

^ permalink raw reply

* [PATCH v5 1/3] arm64: ptrace: reload a syscall number after ptrace operations
From: Kees Cook @ 2014-07-23 15:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <53CF5E53.3060409@linaro.org>

On Wed, Jul 23, 2014 at 12:03 AM, AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:
> On 07/23/2014 05:15 AM, Kees Cook wrote:
>>
>> On Tue, Jul 22, 2014 at 2:14 AM, AKASHI Takahiro
>> <takahiro.akashi@linaro.org> wrote:
>>>
>>> Arm64 holds a syscall number in w8(x8) register. Ptrace tracer may change
>>> its value either to:
>>>    * any valid syscall number to alter a system call, or
>>>    * -1 to skip a system call
>>>
>>> This patch implements this behavior by reloading that value into
>>> syscallno
>>> in struct pt_regs after tracehook_report_syscall_entry() or
>>> secure_computing(). In case of '-1', a return value of system call can
>>> also
>>> be changed by the tracer setting the value to x0 register, and so
>>> sys_ni_nosyscall() should not be called.
>>>
>>> See also:
>>>      42309ab4, ARM: 8087/1: ptrace: reload syscall number after
>>>                secure_computing() check
>>>
>>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
>>> ---
>>>   arch/arm64/kernel/entry.S  |    2 ++
>>>   arch/arm64/kernel/ptrace.c |   13 +++++++++++++
>>>   2 files changed, 15 insertions(+)
>>>
>>> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
>>> index 5141e79..de8bdbc 100644
>>> --- a/arch/arm64/kernel/entry.S
>>> +++ b/arch/arm64/kernel/entry.S
>>> @@ -628,6 +628,8 @@ ENDPROC(el0_svc)
>>>   __sys_trace:
>>>          mov     x0, sp
>>>          bl      syscall_trace_enter
>>> +       cmp     w0, #-1                         // skip syscall?
>>> +       b.eq    ret_to_user
>>>          adr     lr, __sys_trace_return          // return address
>>>          uxtw    scno, w0                        // syscall number
>>> (possibly new)
>>>          mov     x1, sp                          // pointer to regs
>>> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
>>> index 70526cf..100d7d1 100644
>>> --- a/arch/arm64/kernel/ptrace.c
>>> +++ b/arch/arm64/kernel/ptrace.c
>>> @@ -21,6 +21,7 @@
>>>
>>>   #include <linux/audit.h>
>>>   #include <linux/compat.h>
>>> +#include <linux/errno.h>
>>>   #include <linux/kernel.h>
>>>   #include <linux/sched.h>
>>>   #include <linux/mm.h>
>>> @@ -1109,9 +1110,21 @@ static void tracehook_report_syscall(struct
>>> pt_regs *regs,
>>>
>>>   asmlinkage int syscall_trace_enter(struct pt_regs *regs)
>>>   {
>>> +       unsigned long saved_x0, saved_x8;
>>> +
>>> +       saved_x0 = regs->regs[0];
>>> +       saved_x8 = regs->regs[8];
>>> +
>>>          if (test_thread_flag(TIF_SYSCALL_TRACE))
>>>                  tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
>>>
>>> +       regs->syscallno = regs->regs[8];
>>> +       if ((long)regs->syscallno == ~0UL) { /* skip this syscall */
>>> +               regs->regs[8] = saved_x8;
>>> +               if (regs->regs[0] == saved_x0) /* not changed by user */
>>> +                       regs->regs[0] = -ENOSYS;
>>
>>
>> I'm not sure this is right compared to other architectures. Generally
>> when a tracer performs a syscall skip, it's up to them to also adjust
>> the return value. They may want to be faking a syscall, and what if
>> the value they want to return happens to be what x0 was going into the
>> tracer? It would have no way to avoid this -ENOSYS case. I think
>> things are fine without this test.
>
>
> Yeah, I know this issue, but was not sure that setting a return value
> is mandatory. (x86 seems to return -ENOSYS by default if not explicitly
> specified.)
> Is "fake a system call" a more appropriate word than "skip"?

I think this is just a matter of semantics and perspective. From the
kernel's perspective, it's always a "skip" since the syscall is never
actually executed. But from the perspective of userspace, it's really
up to the tracer to decide how it should be seen: the tracer could
return -ENOSYS, or a fake return value, etc. But generally, I think
"skip" is the most accurate term for this.

-Kees

-- 
Kees Cook
Chrome OS Security

^ permalink raw reply


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