* [PATCH 0/2] minor GXL and GXM improvements
From: Martin Blumenstingl @ 2016-11-23 16:20 UTC (permalink / raw)
To: linux-arm-kernel
This series adds SCPI support to GXL and GXM SoCs by moving the nodes
to meson-gx.dtsi. Additionally this updates the compatible string to
match the recent changes, see [0]
Now that we have SCPI support for GXM we can also use it to configure
the CPU cores using the SCPI DVFS clocks.
[0] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/001632.html
Martin Blumenstingl (2):
ARM64: dts: meson-gx: move the SCPI and SRAM nodes to meson-gx
ARM64: dts: meson-gxm: add SCPI configuration for GXM
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 45 +++++++++++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 57 -----------------------------
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 9 +++++
3 files changed, 54 insertions(+), 57 deletions(-)
--
2.10.2
^ permalink raw reply
* [PATCH 1/2] ARM64: dts: meson-gx: move the SCPI and SRAM nodes to meson-gx
From: Martin Blumenstingl @ 2016-11-23 16:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161123162040.24843-1-martin.blumenstingl@googlemail.com>
SCPI and SRAM are identical on GXBB and GXL. Moving the corresponding
nodes to meson-gx adds support for the thermal sensor on GXL based
devices.
While here, also rename the second compatible string because
"arm,legacy-scpi" was replaced by "arm,scpi-pre-1.0".
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 45 +++++++++++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 57 -----------------------------
2 files changed, 45 insertions(+), 57 deletions(-)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index fc033c0..47ab306 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -65,6 +65,7 @@
reg = <0x0 0x0>;
enable-method = "psci";
next-level-cache = <&l2>;
+ clocks = <&scpi_dvfs 0>;
};
cpu1: cpu at 1 {
@@ -73,6 +74,7 @@
reg = <0x0 0x1>;
enable-method = "psci";
next-level-cache = <&l2>;
+ clocks = <&scpi_dvfs 0>;
};
cpu2: cpu at 2 {
@@ -81,6 +83,7 @@
reg = <0x0 0x2>;
enable-method = "psci";
next-level-cache = <&l2>;
+ clocks = <&scpi_dvfs 0>;
};
cpu3: cpu at 3 {
@@ -89,6 +92,7 @@
reg = <0x0 0x3>;
enable-method = "psci";
next-level-cache = <&l2>;
+ clocks = <&scpi_dvfs 0>;
};
l2: l2-cache0 {
@@ -153,6 +157,28 @@
};
};
+ scpi {
+ compatible = "amlogic,meson-gxbb-scpi", "arm,scpi-pre-1.0";
+ mboxes = <&mailbox 1 &mailbox 2>;
+ shmem = <&cpu_scp_lpri &cpu_scp_hpri>;
+
+ clocks {
+ compatible = "arm,scpi-clocks";
+
+ scpi_dvfs: scpi_clocks at 0 {
+ compatible = "arm,scpi-dvfs-clocks";
+ #clock-cells = <1>;
+ clock-indices = <0>;
+ clock-output-names = "vcpu";
+ };
+ };
+
+ scpi_sensors: sensors {
+ compatible = "arm,scpi-sensors";
+ #thermal-sensor-cells = <1>;
+ };
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <2>;
@@ -264,6 +290,25 @@
#address-cells = <0>;
};
+ sram: sram at c8000000 {
+ compatible = "amlogic,meson-gxbb-sram", "mmio-sram";
+ reg = <0x0 0xc8000000 0x0 0x14000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x0 0xc8000000 0x14000>;
+
+ cpu_scp_lpri: scp-shmem at 0 {
+ compatible = "amlogic,meson-gxbb-scp-shmem";
+ reg = <0x13000 0x400>;
+ };
+
+ cpu_scp_hpri: scp-shmem at 200 {
+ compatible = "amlogic,meson-gxbb-scp-shmem";
+ reg = <0x13400 0x400>;
+ };
+ };
+
aobus: aobus at c8100000 {
compatible = "simple-bus";
reg = <0x0 0xc8100000 0x0 0x100000>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index ac5ad3b..76465e7 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -50,28 +50,6 @@
/ {
compatible = "amlogic,meson-gxbb";
- scpi {
- compatible = "amlogic,meson-gxbb-scpi";
- mboxes = <&mailbox 1 &mailbox 2>;
- shmem = <&cpu_scp_lpri &cpu_scp_hpri>;
-
- clocks {
- compatible = "arm,scpi-clocks";
-
- scpi_dvfs: scpi_clocks at 0 {
- compatible = "arm,scpi-dvfs-clocks";
- #clock-cells = <1>;
- clock-indices = <0>;
- clock-output-names = "vcpu";
- };
- };
-
- scpi_sensors: sensors {
- compatible = "arm,scpi-sensors";
- #thermal-sensor-cells = <1>;
- };
- };
-
soc {
usb0_phy: phy at c0000000 {
compatible = "amlogic,meson-gxbb-usb2-phy";
@@ -93,25 +71,6 @@
status = "disabled";
};
- sram: sram at c8000000 {
- compatible = "amlogic,meson-gxbb-sram", "mmio-sram";
- reg = <0x0 0xc8000000 0x0 0x14000>;
-
- #address-cells = <1>;
- #size-cells = <1>;
- ranges = <0 0x0 0xc8000000 0x14000>;
-
- cpu_scp_lpri: scp-shmem at 0 {
- compatible = "amlogic,meson-gxbb-scp-shmem";
- reg = <0x13000 0x400>;
- };
-
- cpu_scp_hpri: scp-shmem at 200 {
- compatible = "amlogic,meson-gxbb-scp-shmem";
- reg = <0x13400 0x400>;
- };
- };
-
usb0: usb at c9000000 {
compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
reg = <0x0 0xc9000000 0x0 0x40000>;
@@ -138,22 +97,6 @@
};
};
-&cpu0 {
- clocks = <&scpi_dvfs 0>;
-};
-
-&cpu1 {
- clocks = <&scpi_dvfs 0>;
-};
-
-&cpu2 {
- clocks = <&scpi_dvfs 0>;
-};
-
-&cpu3 {
- clocks = <&scpi_dvfs 0>;
-};
-
&cbus {
spifc: spi at 8c80 {
compatible = "amlogic,meson-gxbb-spifc";
--
2.10.2
^ permalink raw reply related
* [PATCH 2/2] ARM64: dts: meson-gxm: add SCPI configuration for GXM
From: Martin Blumenstingl @ 2016-11-23 16:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161123162040.24843-1-martin.blumenstingl@googlemail.com>
This adds the SCPI DVFS clock index and configures the CPU cores
accordingly.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
index c1974bb..2b1d276e 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
@@ -85,6 +85,7 @@
reg = <0x0 0x100>;
enable-method = "psci";
next-level-cache = <&l2>;
+ clocks = <&scpi_dvfs 1>;
};
cpu5: cpu at 101 {
@@ -93,6 +94,7 @@
reg = <0x0 0x101>;
enable-method = "psci";
next-level-cache = <&l2>;
+ clocks = <&scpi_dvfs 1>;
};
cpu6: cpu at 102 {
@@ -101,6 +103,7 @@
reg = <0x0 0x102>;
enable-method = "psci";
next-level-cache = <&l2>;
+ clocks = <&scpi_dvfs 1>;
};
cpu7: cpu at 103 {
@@ -109,6 +112,12 @@
reg = <0x0 0x103>;
enable-method = "psci";
next-level-cache = <&l2>;
+ clocks = <&scpi_dvfs 1>;
};
};
};
+
+&scpi_dvfs {
+ clock-indices = <0 1>;
+ clock-output-names = "vbig", "vlittle";
+};
--
2.10.2
^ permalink raw reply related
* [PATCH 2/3] pinctrl: New driver for TI DA8XX/OMAP-L138/AM18XX pinconf
From: David Lechner @ 2016-11-23 16:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <88b3d16b-6e5b-ea75-d770-35d9adc6c677@ti.com>
On 11/23/2016 05:04 AM, Sekhar Nori wrote:
> On Wednesday 23 November 2016 08:59 AM, David Lechner wrote:
>> This adds a new driver for pinconf on TI DA8XX/OMAP-L138/AM18XX. These
>
> s/DA8XX/DA850/
>
>> SoCs have a separate controller for controlling pullup/pulldown groups.
>>
>> Signed-off-by: David Lechner <david@lechnology.com>
>
>> +static const char *da850_pupd_get_get_group_name(struct pinctrl_dev *pctldev,
>> + unsigned int selector)
>> +{
>> + return da850_pupd_group_names[selector];
>> +}
>> +
>> +static int da850_pupd_get_get_group_pins(struct pinctrl_dev *pctldev,
>> + unsigned int selector,
>> + const unsigned int **pins,
>> + unsigned int *num_pins)
>> +{
>> + *num_pins = 0;
>> +
>> + return 0;
>> +}
>
> usage of get_get_ in the function names above is odd.
Will fix (copy/paste error)
>
> Thanks,
> Sekhar
>
^ permalink raw reply
* [PATCH 3/3] ARM: dts: da850: Add node for pullup/pulldown pinconf
From: David Lechner @ 2016-11-23 16:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8c3e6535-4b79-9731-f801-c13f007e48ab@ti.com>
On 11/23/2016 05:12 AM, Sekhar Nori wrote:
> On Wednesday 23 November 2016 08:59 AM, David Lechner wrote:
>> This SoC has a separate pin controller for configuring pullup/pulldown
>> bias on groups of pins.
>>
>> Signed-off-by: David Lechner <david@lechnology.com>
>> ---
>> arch/arm/boot/dts/da850.dtsi | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
>> index 8945815..1c0224c 100644
>> --- a/arch/arm/boot/dts/da850.dtsi
>> +++ b/arch/arm/boot/dts/da850.dtsi
>> @@ -210,6 +210,11 @@
>> };
>>
>> };
>> + pinconf: pin-controller at 22c00c {
>> + compatible = "ti,da850-pupd";
>> + reg = <0x22c00c 0x8>;
>> + status = "disabled";
>> + };
>
> Can you please place this below the i2c1 node. I am trying to keep the
> nodes sorted by unit address. I know thats broken in many places today,
> but lets add the new ones where they should eventually end up.
I can do this, but it seems that the predominant sorting pattern here is
to keep subsystems together (e.g. all i2c are together, all uart are
together, etc.)
Would a separate patch to sort everything by unit address to get this
cleaned up be acceptable?
>
> Thanks,
> Sekhar
>
^ permalink raw reply
* [PATCH 1/7] add binding for stm32 multifunctions timer driver
From: Benjamin Gaignard @ 2016-11-23 17:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161123092148.GO10134@dell.home>
2016-11-23 10:21 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
>
>> 2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
>> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>> >
>> >> Add bindings information for stm32 timer MFD
>> >>
>> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
>> >> ---
>> >> .../devicetree/bindings/mfd/stm32-timer.txt | 53 ++++++++++++++++++++++
>> >> 1 file changed, 53 insertions(+)
>> >> create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >>
>> >> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >> new file mode 100644
>> >> index 0000000..3cefce1
>> >> --- /dev/null
>> >> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >> @@ -0,0 +1,53 @@
>> >> +STM32 multifunctions timer driver
>> >
>> > "STM32 Multi-Function Timer/PWM device bindings"
>> >
>> > Doesn't this shared device have a better name?
>>
>> In SoC documentation those hardware blocks are named "advanced-control
>> timers", "general purpose timers" or "basic timers"
>> "stm32-timer" name is already used for clock source driver, that why I
>> have prefix it with mfd
>
> MFD is a Linuxisum and has no place in hardware description.
>
> Please used one of the names you mentioned above.
I will go for "st,stm32-advanced-timer"
>
> Hopefully the one that best fits.
>
>> >> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
>> >
>> > No need for this sentence.
>> >
>> OK
>>
>> >> +Required parameters:
>> >> +- compatible: must be one of the follow value:
>> >> + "st,stm32-mfd-timer1"
>> >> + "st,stm32-mfd-timer2"
>> >> + "st,stm32-mfd-timer3"
>> >> + "st,stm32-mfd-timer4"
>> >> + "st,stm32-mfd-timer5"
>> >> + "st,stm32-mfd-timer6"
>> >> + "st,stm32-mfd-timer7"
>> >> + "st,stm32-mfd-timer8"
>> >> + "st,stm32-mfd-timer9"
>> >> + "st,stm32-mfd-timer10"
>> >> + "st,stm32-mfd-timer11"
>> >> + "st,stm32-mfd-timer12"
>> >> + "st,stm32-mfd-timer13"
>> >> + "st,stm32-mfd-timer14"
>> >
>> > We don't normally number devices.
>> >
>> > What's stopping you from simply doing:
>> >
>> > pwm1: pwm1 at 40010000 {
>> > compatible = "st,stm32-pwm";
>> > };
>> > pwm2: pwm1 at 40020000 {
>> > compatible = "st,stm32-pwm";
>> > };
>> > pwm3: pwm1 at 40030000 {
>> > compatible = "st,stm32-pwm";
>> > };
>> >
>>
>> Because each instance of the hardware is slightly different: number of
>> pwm channels, triggers capabilities, etc ..
>> so I need to distinguish them.
>> Since it look to be a problem I will follow your suggestion and add a
>> property this driver to be able to identify each instance.
>> Do you think that "id" parameter (integer for 1 to 14) is acceptable ?
>
> Unfortunately not. IDs aren't allowed in DT.
>
> What about "pwm-chans" and "trigger"?
>
> pwm-chans : Number of available channels available
For pwm I need those 4 properties:
st,pwm-number: the number of PWM devices
st,complementary: if exist have complementary ouput
st,32bit-counter: if exist have 32 bits counter
st,breakinput-polarity: if set enable break input feature.
Is it acceptable from pwm maintainer point of view ?
> trigger : Boolean value specifying whether a timer is present
Following our discussion on IRC I will try to code for your proposal:
advanced-timer at 40010000 {
compatible = "st,stm32-advanced-timer";
reg = <0x40010000 0x400>;
clocks = <&rcc 0 160>;
clock-names = "clk_int";
pwm at 0 {
compatible = "st,stm32-pwm";
st,pwm-number= <4>;
st,complementary;
st,breakinput;
};
timer at 0 {
reg = <1>;
compatible = "st,stm32-iio-timer";
interrupts = <27>;
triggers = <5 2 3 4>;
};
};
triggers parameter will be used to know which trigger are valid for
the IIO device
[snip]
^ permalink raw reply
* [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on Hip06
From: Arnd Bergmann @ 2016-11-23 17:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <EE11001F9E5DDD47B7634E2F8A612F2E1F931E08@lhreml507-mbx>
On Wednesday, November 23, 2016 3:22:33 PM CET Gabriele Paoloni wrote:
> From: Arnd Bergmann [mailto:arnd at arndb.de]
> > On Friday, November 18, 2016 5:03:11 PM CET Gabriele Paoloni wrote:
> > > I think this is effectively what we are doing so far with patch 2/3.
> > > The problem with this patch is that we are carving out a "forbidden"
> > > IO tokens range that goes from 0 to PCIBIOS_MIN_IO.
> > >
> > > I think that the proper solution would be to have the LPC driver to
> > > set the carveout threshold used in pci_register_io_range(),
> > > pci_pio_to_address(), pci_address_to_pio(), but this would impose
> > > a probe dependency on the LPC itself that should be probed before
> > > the PCI controller (or before any other devices calling these
> > > functions...)
> >
> > Why do you think the order matters? My point was that we should
> > be able to register any region of logical port numbers for any
> > bus here.
>
> Maybe I have not followed well so let's roll back to your previous
> comment...
>
> "we need to associate a bus address with a logical Linux port number,
> both in of_address_to_resource and in inb()/outb()"
>
> Actually of_address_to_resource() returns the port number to used
> in inb/outb(); inb() and outb() add the port number to PCI_IOBASE
> to rd/wr to the right virtual address.
Correct.
> Our LPC cannot operate on the virtual address and it operates on
> a bus address range that for LPC is also equal to the cpu address
> range and goes from 0 to 0x1000.
There is no "cpu address" here, otherwise this is correct.
> Now as I understand it is risky and not appropriate to reserve
> the logical port numbers from 0 to 0x1000 or to whatever other
> upper bound because existing systems may rely on these port numbers
> retrieved by __of_address_to_resource().
Right again.
> In this scenario I think the best thing to do would be
> in the probe function of the LPC driver:
> 1) call pci_register_io_range() passing [0, 0x1000] (that is the
> range for LPC)
pci_register_io_range() takes a physical address, not a port number,
so that would not be appropriate as you say above. We can however
add a variant that reserves a range of port numbers in io_range_list
for an indirect access method.
> 2) retrieve the logical port numbers associated to the LPC range
> by calling pci_address_to_pio() for 0 and 0x1000 and assign
> them to extio_ops_node->start and extio_ops_node->end
Again, calling pci_address_to_pio() doesn't seem right here, because
we don't have a phys_addr_t address
> 3) implement the LPC accessors to operate on the logical ports
> associated to the LPC range (in practice in the accessors
> implementation we will call pci_pio_to_address to retrieve
> the cpu address to operate on)
Please don't proliferate the use of
pci_pio_to_address/pci_address_to_pio here, computing the physical
address from the logical address is trivial, you just need to
subtract the start of the range that you already use when matching
the port number range.
The only thing we need here is to make of_address_to_resource()
return the correct logical port number that was registered for
a given host device when asked to translate an address that
does not have a CPU address associated with it.
Arnd
^ permalink raw reply
* [PATCH 1/4] serial: core: Add LED trigger support
From: Mathieu Poirier @ 2016-11-23 17:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161123100106.15969-2-s.hauer@pengutronix.de>
On Wed, Nov 23, 2016 at 11:01:03AM +0100, Sascha Hauer wrote:
> With this patch the serial core provides LED triggers for RX and TX.
>
> As the serial core layer does not know when the hardware actually sends
> or receives characters, this needs help from the UART drivers. The
> LED triggers are registered in uart_add_led_triggers() called from
> the UART drivers which want to support LED triggers. All the driver
> has to do then is to call uart_led_trigger_[tx|rx] to indicate
> activite.
Hello Sascha,
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> drivers/tty/serial/serial_core.c | 73 ++++++++++++++++++++++++++++++++++++++++
> include/linux/serial_core.h | 10 ++++++
> 2 files changed, 83 insertions(+)
>
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index f2303f3..3e8afb7 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -34,6 +34,7 @@
> #include <linux/serial_core.h>
> #include <linux/delay.h>
> #include <linux/mutex.h>
> +#include <linux/leds.h>
>
> #include <asm/irq.h>
> #include <asm/uaccess.h>
> @@ -2703,6 +2704,77 @@ static const struct attribute_group tty_dev_attr_group = {
> .attrs = tty_dev_attrs,
> };
>
> +void uart_led_trigger_tx(struct uart_port *uport)
> +{
> + unsigned long delay = 50;
> +
> + led_trigger_blink_oneshot(uport->led_trigger_tx, &delay, &delay, 0);
> +}
> +
> +void uart_led_trigger_rx(struct uart_port *uport)
> +{
> + unsigned long delay = 50;
> +
> + led_trigger_blink_oneshot(uport->led_trigger_rx, &delay, &delay, 0);
For both rx/tx the core constrains the delay_on/off along with the inversion.
Instead of adding the led_trigger_rx/tx and led_trigger_rx/tx_name to the
struct uart_port, wouldn't it be better to add a new struct led_trigger that
would encapsulate those along wit the on/off delay and the inversion?
That way those values could be communicated to the core at registration time
instead of hard-coding things.
> +}
> +
> +/**
> + * uart_add_led_triggers - register LED triggers for a UART
> + * @drv: pointer to the uart low level driver structure for this port
> + * @uport: uart port structure to use for this port.
> + *
> + * Called by the driver to register LED triggers for a UART. It's the
> + * drivers responsibility to call uart_led_trigger_rx/tx on received
> + * and transmitted chars then.
> + */
> +int uart_add_led_triggers(struct uart_driver *drv, struct uart_port *uport)
> +{
> + int ret;
> +
> + if (!IS_ENABLED(CONFIG_LEDS_TRIGGERS))
> + return 0;
Since this is a public interface, checking for valid led_trigger_tx/rx before
moving on with the rest of the initialisation is probably a good idea.
Thanks,
Mathieu
> +
> + uport->led_trigger_tx_name = kasprintf(GFP_KERNEL, "%s%d-tx",
> + drv->dev_name, uport->line);
> + uport->led_trigger_rx_name = kasprintf(GFP_KERNEL, "%s%d-rx",
> + drv->dev_name, uport->line);
> + if (!uport->led_trigger_tx_name || !uport->led_trigger_rx_name) {
> + ret = -ENOMEM;
> + goto err_alloc;
> + }
> +
> + led_trigger_register_simple(uport->led_trigger_tx_name,
> + &uport->led_trigger_tx);
> + led_trigger_register_simple(uport->led_trigger_rx_name,
> + &uport->led_trigger_rx);
> +
> + return 0;
> +
> +err_alloc:
> + kfree(uport->led_trigger_tx_name);
> + kfree(uport->led_trigger_rx_name);
> +
> + return ret;
> +}
> +
> +/**
> + * uart_remove_led_triggers - remove LED triggers
> + * @drv: pointer to the uart low level driver structure for this port
> + * @uport: uart port structure to use for this port.
> + *
> + * Remove LED triggers previously registered with uart_add_led_triggers
> + */
> +void uart_remove_led_triggers(struct uart_port *uport)
> +{
> + if (uport->led_trigger_rx)
> + led_trigger_unregister_simple(uport->led_trigger_rx);
> + kfree(uport->led_trigger_rx_name);
> +
> + if (uport->led_trigger_tx)
> + led_trigger_unregister_simple(uport->led_trigger_tx);
> + kfree(uport->led_trigger_tx_name);
> +}
> +
> /**
> * uart_add_one_port - attach a driver-defined port structure
> * @drv: pointer to the uart low level driver structure for this port
> @@ -2872,6 +2944,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
> WARN_ON(atomic_dec_return(&state->refcount) < 0);
> wait_event(state->remove_wait, !atomic_read(&state->refcount));
> state->uart_port = NULL;
> +
> mutex_unlock(&port->mutex);
> out:
> mutex_unlock(&port_mutex);
> diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
> index 3442014..1b0a169 100644
> --- a/include/linux/serial_core.h
> +++ b/include/linux/serial_core.h
> @@ -29,6 +29,7 @@
> #include <linux/tty.h>
> #include <linux/mutex.h>
> #include <linux/sysrq.h>
> +#include <linux/leds.h>
> #include <uapi/linux/serial_core.h>
>
> #ifdef CONFIG_SERIAL_CORE_CONSOLE
> @@ -249,6 +250,10 @@ struct uart_port {
> const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
> struct serial_rs485 rs485;
> void *private_data; /* generic platform data pointer */
> + struct led_trigger *led_trigger_rx;
> + char *led_trigger_rx_name;
> + struct led_trigger *led_trigger_tx;
> + char *led_trigger_tx_name;
> };
>
> static inline int serial_port_in(struct uart_port *up, int offset)
> @@ -392,6 +397,11 @@ void uart_console_write(struct uart_port *port, const char *s,
> unsigned int count,
> void (*putchar)(struct uart_port *, int));
>
> +int uart_add_led_triggers(struct uart_driver *drv, struct uart_port *uport);
> +void uart_remove_led_triggers(struct uart_port *uport);
> +void uart_led_trigger_tx(struct uart_port *port);
> +void uart_led_trigger_rx(struct uart_port *port);
> +
> /*
> * Port/driver registration/removal
> */
> --
> 2.10.2
>
^ permalink raw reply
* [PATCH] ARM: dts: sunxi: Enable UEXT related nodes for Olimex A20 SOM EVB
From: Emmanuel Vadot @ 2016-11-23 17:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161123080350.fstwdfndghk7c5xx@lukather>
On Wed, 23 Nov 2016 09:03:50 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> On Mon, Nov 21, 2016 at 05:49:11PM +0100, Emmanuel Vadot wrote:
> > UEXT are Universal EXTension connector from Olimex. They embed i2c, spi
> > and uart pins along power in one connector and are found on most,
> > if not all, Olimex boards.
> > The Olimex A20 SOM EVB have two UEXT connector so enable the nodes found on
> > those two connectors.
> >
> > Signed-off-by: Emmanuel Vadot <manu@bidouilliste.com>
>
> Fixed the indentation of the spi pinctrl cells, and applied.
>
> Please note that I'm note planning to send any new pull request, so
> this will likely end up in 4.11.
>
> Thanks!
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
Sorry about the indentation, I'll be more carefull next time.
Thank you.
--
Emmanuel Vadot <manu@bidouilliste.com> <manu@freebsd.org>
^ permalink raw reply
* System/uncore PMUs and unit aggregation
From: Mark Rutland @ 2016-11-23 17:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161118111017.GA22798@hardcore>
On Fri, Nov 18, 2016 at 12:10:17PM +0100, Jan Glauber wrote:
> On Thu, Nov 17, 2016 at 06:17:08PM +0000, Will Deacon wrote:
> > Speaking to Mark earlier today, we came up with the following rough rules
> > for drivers that present multiple hardware units as a single PMU:
> >
> > 1. If the units share some part of the programming interface (e.g. control
> > registers or interrupts), then they must be handled by the same PMU.
> > Otherwise, they should be treated independently as separate PMU
> > instances.
>
> Can you elaborate why they should be treated independent in the later
> case? What is the problem with going through a list and writing the
> control register per unit?
For one thing, event groups spanning those units cannot be scheduled
atomically (some events would be counting while others were not),
violating group semantics.
> > 3. Summing the counters across units is only permitted if the units
> > can all be started and stopped atomically. Otherwise, the counters
> > should be exposed individually. It's up to the driver author to
> > decide what makes sense to sum.
>
> Do you mean started/stopped atomically across units?
Yes. If some units are counting while others are not, values can be
skewed, and therefore potentially misleading.
> > For Cavium ThunderX, it's not clear whether or not the individual units
> > could be expressed as separate PMUs, or whether they're caught by one of
> > the rules above. The Qualcomm L2 looks like it's doing the right thing
> > and we can't quite work out what the Hisilicon Hip0x topology looks like,
> > since the interaction with djtag is confusing.
>
> On Cavium ThunderX the current patches add 4 PMU types, which unfortunately
> are all handled different. The L2C-TAD and OCX-TLK have control
> registers per unit. The LMC and L2C-CBC don't have control registers,
> (free-running counters). So rule 1 might be too restrictive.
>
> I've not looked into groups, would these allow to merge counters from
> different PMUs in the kernel?
No; event groups are strictly single PMU, with the sole exception that
software events may be placed inside a hardware event group (since
there's no start/stop logic required for SW events).
Thanks,
Mark.
^ permalink raw reply
* [PATCH 2/4] ARM: dts: exynos: specify snps,dwmac in compatible string for gmac
From: Krzysztof Kozlowski @ 2016-11-23 17:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479911091-19812-1-git-send-email-niklass@axis.com>
On Wed, Nov 23, 2016 at 03:24:51PM +0100, Niklas Cassel wrote:
> From: Niklas Cassel <niklas.cassel@axis.com>
>
> devicetree binding for stmmac states:
> - compatible: Should be "snps,dwmac-<ip_version>", "snps,dwmac"
> For backwards compatibility: "st,spear600-gmac" is also supported.
>
> No functional change intended.
>
> Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
> ---
> arch/arm/boot/dts/exynos5440.dtsi | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Thanks, applied.
Best regards,
Krzysztof
^ permalink raw reply
* Tearing down DMA transfer setup after DMA client has finished
From: Måns Rullgård @ 2016-11-23 17:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <58358E79.5050404@free.fr>
Mason <slash.tmp@free.fr> writes:
> On 23/11/2016 13:13, M?ns Rullg?rd wrote:
>
>> Mason wrote:
>>
>>> On my platform, setting up a DMA transfer is a two-step process:
>>>
>>> 1) configure the "switch box" to connect a device to a memory channel
>>> 2) configure the transfer details (address, size, command)
>>>
>>> When the transfer is done, the sbox setup can be torn down,
>>> and the DMA driver can start another transfer.
>>>
>>> The current software architecture for my NFC (NAND Flash controller)
>>> driver is as follows (for one DMA transfer).
>>>
>>> sg_init_one
>>> dma_map_sg
>>> dmaengine_prep_slave_sg
>>> dmaengine_submit
>>> dma_async_issue_pending
>>> configure_NFC_transfer
>>> wait_for_IRQ_from_DMA_engine // via DMA_PREP_INTERRUPT
>>> wait_for_NFC_idle
>>> dma_unmap_sg
>>>
>>> The problem is that the DMA driver tears down the sbox setup
>>> as soon as it receives the IRQ. However, when writing to the
>>> device, the interrupt only means "I have pushed all data from
>>> memory to the memory channel". These data have not reached
>>> the device yet, and may still be "in flight". Thus the sbox
>>> setup can only be torn down after the NFC is idle.
>>>
>>> How do I call back into the DMA driver after wait_for_NFC_idle,
>>> to request sbox tear down?
>>>
>>> The new architecture would become:
>>>
>>> sg_init_one
>>> dma_map_sg
>>> dmaengine_prep_slave_sg
>>> dmaengine_submit
>>> dma_async_issue_pending
>>> configure_NFC_transfer
>>> wait_for_IRQ_from_DMA_engine // via DMA_PREP_INTERRUPT
>>> wait_for_NFC_idle
>>> request_sbox_tear_down /*** HOW TO DO THAT ***/
>>> dma_unmap_sg
>>>
>>> As far as I can tell, my NFC driver should call dmaengine_synchronize ??
>>> (In other words request_sbox_tear_down == dmaengine_synchronize)
>>>
>>> So the DMA driver should implement the device_synchronize hook,
>>> and tear the sbox down in that function.
>>>
>>> Is that correct? Or am I on the wrong track?
>>
>> dmaengine_synchronize() is not meant for this. See the documentation:
>>
>> /**
>> * dmaengine_synchronize() - Synchronize DMA channel termination
>> * @chan: The channel to synchronize
>> *
>> * Synchronizes to the DMA channel termination to the current context. When this
>> * function returns it is guaranteed that all transfers for previously issued
>> * descriptors have stopped and and it is safe to free the memory assoicated
>> * with them. Furthermore it is guaranteed that all complete callback functions
>> * for a previously submitted descriptor have finished running and it is safe to
>> * free resources accessed from within the complete callbacks.
>> *
>> * The behavior of this function is undefined if dma_async_issue_pending() has
>> * been called between dmaengine_terminate_async() and this function.
>> *
>> * This function must only be called from non-atomic context and must not be
>> * called from within a complete callback of a descriptor submitted on the same
>> * channel.
>> */
>>
>> This is for use after a dmaengine_terminate_async() call to wait for the
>> dma engine to finish whatever it was doing. This is not the problem
>> here. Your problem is that the dma engine interrupt fires before the
>> transfer is actually complete. Although you get an indication from the
>> target device when it has received all the data, there is no way to make
>> the dma driver wait for this.
>
> Hello Mans,
>
> I'm confused. Are you saying there is no solution to my problem
> within the existing DMA framework?
>
> In its current form, the tangox-dma.c driver will fail randomly
> for writes to a device (SATA, NFC).
>
> Maybe an extra hook can be added to the DMA framework?
>
> I'd like to hear from the framework's maintainers. Perhaps they
> can provide some guidance.
You could have the dma descriptor callback wait for the receiving device
to finish. Bear in mind this runs from a tasklet, so it's not allowed
to sleep.
--
M?ns Rullg?rd
^ permalink raw reply
* [PATCH 1/9] clocksource/drivers/rockchip_timer: split bc_timer into rk_timer and rk_clock_event_device
From: Alexander Kochetkov @ 2016-11-23 17:29 UTC (permalink / raw)
To: linux-arm-kernel
Move ce field out of struct bc_timer into struct rk_clock_event_device,
rename struct bc_timer to struct rk_timer.
Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
---
drivers/clocksource/rockchip_timer.c | 33 ++++++++++++++++++++++-----------
1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index 23e267a..6d68d4c 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -29,18 +29,28 @@
#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
#define TIMER_INT_UNMASK (1 << 2)
-struct bc_timer {
- struct clock_event_device ce;
+struct rk_timer {
void __iomem *base;
void __iomem *ctrl;
u32 freq;
};
-static struct bc_timer bc_timer;
+struct rk_clock_event_device {
+ struct clock_event_device ce;
+ struct rk_timer timer;
+};
+
+static struct rk_clock_event_device bc_timer;
+
+static inline struct rk_clock_event_device*
+rk_clock_event_device(struct clock_event_device *ce)
+{
+ return container_of(ce, struct rk_clock_event_device, ce);
+}
-static inline struct bc_timer *rk_timer(struct clock_event_device *ce)
+static inline struct rk_timer *rk_timer(struct clock_event_device *ce)
{
- return container_of(ce, struct bc_timer, ce);
+ return &rk_clock_event_device(ce)->timer;
}
static inline void __iomem *rk_base(struct clock_event_device *ce)
@@ -116,16 +126,17 @@ static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
{
struct clock_event_device *ce = &bc_timer.ce;
+ struct rk_timer *timer = &bc_timer.timer;
struct clk *timer_clk;
struct clk *pclk;
int ret = -EINVAL, irq;
- bc_timer.base = of_iomap(np, 0);
- if (!bc_timer.base) {
+ timer->base = of_iomap(np, 0);
+ if (!timer->base) {
pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
return -ENXIO;
}
- bc_timer.ctrl = bc_timer.base + ctrl_reg;
+ timer->ctrl = timer->base + ctrl_reg;
pclk = of_clk_get_by_name(np, "pclk");
if (IS_ERR(pclk)) {
@@ -153,7 +164,7 @@ static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
goto out_timer_clk;
}
- bc_timer.freq = clk_get_rate(timer_clk);
+ timer->freq = clk_get_rate(timer_clk);
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
@@ -181,7 +192,7 @@ static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
goto out_irq;
}
- clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
+ clockevents_config_and_register(ce, timer->freq, 1, UINT_MAX);
return 0;
@@ -190,7 +201,7 @@ out_irq:
out_timer_clk:
clk_disable_unprepare(pclk);
out_unmap:
- iounmap(bc_timer.base);
+ iounmap(timer->base);
return ret;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/9] clocksource/drivers/rockchip_timer: low level routines take rk_timer as parameter
From: Alexander Kochetkov @ 2016-11-23 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479922177-20136-1-git-send-email-al.kochet@gmail.com>
Pass rk_timer instead of clock_event_device to low lever timer routines.
So that code could be reused by clocksource implementation.
Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
---
drivers/clocksource/rockchip_timer.c | 44 ++++++++++++++++++----------------
1 file changed, 24 insertions(+), 20 deletions(-)
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index 6d68d4c..f84f67c 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -63,60 +63,64 @@ static inline void __iomem *rk_ctrl(struct clock_event_device *ce)
return rk_timer(ce)->ctrl;
}
-static inline void rk_timer_disable(struct clock_event_device *ce)
+static inline void rk_timer_disable(struct rk_timer *timer)
{
- writel_relaxed(TIMER_DISABLE, rk_ctrl(ce));
+ writel_relaxed(TIMER_DISABLE, timer->ctrl);
}
-static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
+static inline void rk_timer_enable(struct rk_timer *timer, u32 flags)
{
writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
- rk_ctrl(ce));
+ timer->ctrl);
}
static void rk_timer_update_counter(unsigned long cycles,
- struct clock_event_device *ce)
+ struct rk_timer *timer)
{
- writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0);
- writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1);
+ writel_relaxed(cycles, timer->base + TIMER_LOAD_COUNT0);
+ writel_relaxed(0, timer->base + TIMER_LOAD_COUNT1);
}
-static void rk_timer_interrupt_clear(struct clock_event_device *ce)
+static void rk_timer_interrupt_clear(struct rk_timer *timer)
{
- writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
+ writel_relaxed(1, timer->base + TIMER_INT_STATUS);
}
static inline int rk_timer_set_next_event(unsigned long cycles,
struct clock_event_device *ce)
{
- rk_timer_disable(ce);
- rk_timer_update_counter(cycles, ce);
- rk_timer_enable(ce, TIMER_MODE_USER_DEFINED_COUNT);
+ struct rk_timer *timer = rk_timer(ce);
+ rk_timer_disable(timer);
+ rk_timer_update_counter(cycles, timer);
+ rk_timer_enable(timer, TIMER_MODE_USER_DEFINED_COUNT);
return 0;
}
static int rk_timer_shutdown(struct clock_event_device *ce)
{
- rk_timer_disable(ce);
+ struct rk_timer *timer = rk_timer(ce);
+ rk_timer_disable(timer);
return 0;
}
static int rk_timer_set_periodic(struct clock_event_device *ce)
{
- rk_timer_disable(ce);
- rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
- rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING);
+ struct rk_timer *timer = rk_timer(ce);
+ rk_timer_disable(timer);
+ rk_timer_update_counter(timer->freq / HZ - 1, timer);
+ rk_timer_enable(timer, TIMER_MODE_FREE_RUNNING);
return 0;
}
static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *ce = dev_id;
+ struct rk_timer *timer = rk_timer(ce);
- rk_timer_interrupt_clear(ce);
+ rk_timer_interrupt_clear(timer);
if (clockevent_state_oneshot(ce))
- rk_timer_disable(ce);
+ rk_timer_disable(timer);
ce->event_handler(ce);
@@ -183,8 +187,8 @@ static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
ce->cpumask = cpu_possible_mask;
ce->rating = 250;
- rk_timer_interrupt_clear(ce);
- rk_timer_disable(ce);
+ rk_timer_interrupt_clear(timer);
+ rk_timer_disable(timer);
ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
if (ret) {
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/9] clocksource/drivers/rockchip_timer: drop unused rk_base() and rk_ctrl()
From: Alexander Kochetkov @ 2016-11-23 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479922177-20136-1-git-send-email-al.kochet@gmail.com>
Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
---
drivers/clocksource/rockchip_timer.c | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index f84f67c..2f18166 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -53,16 +53,6 @@ static inline struct rk_timer *rk_timer(struct clock_event_device *ce)
return &rk_clock_event_device(ce)->timer;
}
-static inline void __iomem *rk_base(struct clock_event_device *ce)
-{
- return rk_timer(ce)->base;
-}
-
-static inline void __iomem *rk_ctrl(struct clock_event_device *ce)
-{
- return rk_timer(ce)->ctrl;
-}
-
static inline void rk_timer_disable(struct rk_timer *timer)
{
writel_relaxed(TIMER_DISABLE, timer->ctrl);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/9] clocksource/drivers/rockchip_timer: move TIMER_INT_UNMASK out of rk_timer_enable()
From: Alexander Kochetkov @ 2016-11-23 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479922177-20136-1-git-send-email-al.kochet@gmail.com>
This allow to enable timer without enabling interrupts from it.
As that mode will be used in clocksource implementation.
Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
---
drivers/clocksource/rockchip_timer.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index 2f18166..3b530f9 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -60,8 +60,7 @@ static inline void rk_timer_disable(struct rk_timer *timer)
static inline void rk_timer_enable(struct rk_timer *timer, u32 flags)
{
- writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
- timer->ctrl);
+ writel_relaxed(TIMER_ENABLE | flags, timer->ctrl);
}
static void rk_timer_update_counter(unsigned long cycles,
@@ -82,7 +81,7 @@ static inline int rk_timer_set_next_event(unsigned long cycles,
struct rk_timer *timer = rk_timer(ce);
rk_timer_disable(timer);
rk_timer_update_counter(cycles, timer);
- rk_timer_enable(timer, TIMER_MODE_USER_DEFINED_COUNT);
+ rk_timer_enable(timer, TIMER_MODE_USER_DEFINED_COUNT | TIMER_INT_UNMASK);
return 0;
}
@@ -98,7 +97,7 @@ static int rk_timer_set_periodic(struct clock_event_device *ce)
struct rk_timer *timer = rk_timer(ce);
rk_timer_disable(timer);
rk_timer_update_counter(timer->freq / HZ - 1, timer);
- rk_timer_enable(timer, TIMER_MODE_FREE_RUNNING);
+ rk_timer_enable(timer, TIMER_MODE_FREE_RUNNING | TIMER_INT_UNMASK);
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 5/9] clocksource/drivers/rockchip_timer: implement loading 64bit value into timer
From: Alexander Kochetkov @ 2016-11-23 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479922177-20136-1-git-send-email-al.kochet@gmail.com>
Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
---
drivers/clocksource/rockchip_timer.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index 3b530f9..f4c26be 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -63,11 +63,13 @@ static inline void rk_timer_enable(struct rk_timer *timer, u32 flags)
writel_relaxed(TIMER_ENABLE | flags, timer->ctrl);
}
-static void rk_timer_update_counter(unsigned long cycles,
- struct rk_timer *timer)
+static void rk_timer_update_counter(u64 cycles, struct rk_timer *timer)
{
- writel_relaxed(cycles, timer->base + TIMER_LOAD_COUNT0);
- writel_relaxed(0, timer->base + TIMER_LOAD_COUNT1);
+ u32 lower = cycles & 0xFFFFFFFF;
+ u32 upper = (cycles >> 32) & 0xFFFFFFFF;
+
+ writel_relaxed(lower, timer->base + TIMER_LOAD_COUNT0);
+ writel_relaxed(upper, timer->base + TIMER_LOAD_COUNT1);
}
static void rk_timer_interrupt_clear(struct rk_timer *timer)
--
1.7.9.5
^ permalink raw reply related
* [PATCH 6/9] clocksource/drivers/rockchip_timer: implement reading 64bit value from timer
From: Alexander Kochetkov @ 2016-11-23 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479922177-20136-1-git-send-email-al.kochet@gmail.com>
Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
---
drivers/clocksource/rockchip_timer.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index f4c26be..61787c5 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -19,6 +19,8 @@
#define TIMER_LOAD_COUNT0 0x00
#define TIMER_LOAD_COUNT1 0x04
+#define TIMER_CURRENT_VALUE0 0x08
+#define TIMER_CURRENT_VALUE1 0x0C
#define TIMER_CONTROL_REG3288 0x10
#define TIMER_CONTROL_REG3399 0x1c
#define TIMER_INT_STATUS 0x18
@@ -72,6 +74,25 @@ static void rk_timer_update_counter(u64 cycles, struct rk_timer *timer)
writel_relaxed(upper, timer->base + TIMER_LOAD_COUNT1);
}
+static u64 rk_timer_counter_read(struct rk_timer *timer)
+{
+ u64 counter;
+ u32 lower;
+ u32 upper, old_upper;
+
+ upper = readl_relaxed(timer->base + TIMER_CURRENT_VALUE1);
+ do {
+ old_upper = upper;
+ lower = readl_relaxed(timer->base + TIMER_CURRENT_VALUE0);
+ upper = readl_relaxed(timer->base + TIMER_CURRENT_VALUE1);
+ } while (upper != old_upper);
+
+ counter = upper;
+ counter <<= 32;
+ counter |= lower;
+ return counter;
+}
+
static void rk_timer_interrupt_clear(struct rk_timer *timer)
{
writel_relaxed(1, timer->base + TIMER_INT_STATUS);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 7/9] clocksource/drivers/rockchip_timer: implement clocksource timer
From: Alexander Kochetkov @ 2016-11-23 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479922177-20136-1-git-send-email-al.kochet@gmail.com>
The patch implement stable clocksource for rk3188. It register
one of the timers as clocksource and sched_clock. Also it override
arm_global_timer clocksource using rating property (350).
arm_global_timer enabled on rk3188 provide unstable clocksource.
It's rate depend on ARM CPU rate. As result the command 'sleep 60'
could run either ~60s (with CPU freq 312 MHZ) or ~45s (with CPU
freq 1.6GHz).
In order to use the patch you have to setup the timer using
'rockchip,clocksource' device tree property. timer6 was used as
clocksource in kernel 3.0 from rockchip SDK.
cpufreq-set -f 1.6GHZ
date; sleep 60; date
Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
---
drivers/clocksource/rockchip_timer.c | 79 +++++++++++++++++++++++++++-------
1 file changed, 63 insertions(+), 16 deletions(-)
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index 61787c5..77bea97 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -11,6 +11,7 @@
#include <linux/clockchips.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/sched_clock.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -42,7 +43,13 @@ struct rk_clock_event_device {
struct rk_timer timer;
};
+struct rk_clocksource {
+ struct clocksource cs;
+ struct rk_timer timer;
+};
+
static struct rk_clock_event_device bc_timer;
+static struct rk_clocksource cs_timer;
static inline struct rk_clock_event_device*
rk_clock_event_device(struct clock_event_device *ce)
@@ -139,14 +146,35 @@ static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static cycle_t rk_timer_clocksource_read(struct clocksource *cs)
+{
+ struct rk_clocksource *_cs = container_of(cs, struct rk_clocksource, cs);
+ return ~rk_timer_counter_read(&_cs->timer);
+}
+
+static u64 notrace rk_timer_sched_clock_read(void)
+{
+ struct rk_clocksource *_cs = &cs_timer;
+ return ~rk_timer_counter_read(&_cs->timer);
+}
+
static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
{
- struct clock_event_device *ce = &bc_timer.ce;
- struct rk_timer *timer = &bc_timer.timer;
+ struct clock_event_device *ce = NULL;
+ struct clocksource *cs = NULL;
+ struct rk_timer *timer = NULL;
struct clk *timer_clk;
struct clk *pclk;
int ret = -EINVAL, irq;
+ if (of_property_read_bool(np, "rockchip,clocksource")) {
+ cs = &cs_timer.cs;
+ timer = &cs_timer.timer;
+ } else {
+ ce = &bc_timer.ce;
+ timer = &bc_timer.timer;
+ }
+
timer->base = of_iomap(np, 0);
if (!timer->base) {
pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
@@ -189,26 +217,45 @@ static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg)
goto out_irq;
}
- ce->name = TIMER_NAME;
- ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
- CLOCK_EVT_FEAT_DYNIRQ;
- ce->set_next_event = rk_timer_set_next_event;
- ce->set_state_shutdown = rk_timer_shutdown;
- ce->set_state_periodic = rk_timer_set_periodic;
- ce->irq = irq;
- ce->cpumask = cpu_possible_mask;
- ce->rating = 250;
+ if (ce) {
+ ce->name = TIMER_NAME;
+ ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_DYNIRQ;
+ ce->set_next_event = rk_timer_set_next_event;
+ ce->set_state_shutdown = rk_timer_shutdown;
+ ce->set_state_periodic = rk_timer_set_periodic;
+ ce->irq = irq;
+ ce->cpumask = cpu_possible_mask;
+ ce->rating = 250;
+ }
+
+ if (cs) {
+ cs->name = TIMER_NAME;
+ cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
+ cs->mask = CLOCKSOURCE_MASK(64);
+ cs->read = rk_timer_clocksource_read;
+ cs->rating = 350;
+ }
rk_timer_interrupt_clear(timer);
rk_timer_disable(timer);
- ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
- if (ret) {
- pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
- goto out_irq;
+ if (ce) {
+ ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
+ if (ret) {
+ pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
+ goto out_irq;
+ }
+
+ clockevents_config_and_register(ce, timer->freq, 1, UINT_MAX);
}
- clockevents_config_and_register(ce, timer->freq, 1, UINT_MAX);
+ if (cs) {
+ rk_timer_update_counter(U64_MAX, timer);
+ rk_timer_enable(timer, 0);
+ clocksource_register_hz(cs, timer->freq);
+ sched_clock_register(rk_timer_sched_clock_read, 64, timer->freq);
+ }
return 0;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 8/9] dt-bindings: add rockchip, clocksource property to rk-timer
From: Alexander Kochetkov @ 2016-11-23 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479922177-20136-1-git-send-email-al.kochet@gmail.com>
---
.../bindings/timer/rockchip,rk-timer.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt
index a41b184..ed5392a 100644
--- a/Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt
+++ b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt
@@ -9,6 +9,7 @@ Required properties:
- clocks : must contain an entry for each entry in clock-names
- clock-names : must include the following entries:
"timer", "pclk"
+- rockchip,clocksource: setup the timer as clocksource
Example:
timer: timer at ff810000 {
--
1.7.9.5
^ permalink raw reply related
* [PATCH 9/9] ARM: dts: rockchip: add timer entries to rk3188.dtsi
From: Alexander Kochetkov @ 2016-11-23 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479922177-20136-1-git-send-email-al.kochet@gmail.com>
This is correct configuration borrowed from 3.0 kernel[1].
timer 6 used as clocksource, timers 0, 1, 4 and 5 used
as clockevents.
Timers can do interrupts and work as expected with correct
driver support.
[1] https://github.com/radxa/linux-rockchip/blob/radxa-stable-3.0/arch/arm/mach-rk3188/rk_timer.c
Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
---
arch/arm/boot/dts/rk3188.dtsi | 45 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index 31f81b2..e2f88c8 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -106,6 +106,51 @@
};
};
+ timer0: timer at 20038000 {
+ compatible = "rockchip,rk3288-timer";
+ reg = <0x20038000 0x20>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru SCLK_TIMER0>, <&cru PCLK_TIMER0>;
+ clock-names = "timer", "pclk";
+ status = "disabled";
+ };
+
+ timer1: timer at 20038020 {
+ compatible = "rockchip,rk3288-timer";
+ reg = <0x20038020 0x20>;
+ interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru SCLK_TIMER1>, <&cru PCLK_TIMER0>;
+ clock-names = "timer", "pclk";
+ status = "disabled";
+ };
+
+ timer4: timer at 20038060 {
+ compatible = "rockchip,rk3288-timer";
+ reg = <0x20038060 0x20>;
+ interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru SCLK_TIMER4>, <&cru PCLK_TIMER0>;
+ clock-names = "timer", "pclk";
+ status = "disabled";
+ };
+
+ timer5: timer at 20038080 {
+ compatible = "rockchip,rk3288-timer";
+ reg = <0x20038080 0x20>;
+ interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru SCLK_TIMER5>, <&cru PCLK_TIMER0>;
+ clock-names = "timer", "pclk";
+ status = "disabled";
+ };
+
+ timer6: timer at 200380A0 {
+ compatible = "rockchip,rk3288-timer";
+ reg = <0x200380A0 0x20>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru SCLK_TIMER6>, <&cru PCLK_TIMER0>;
+ clock-names = "timer", "pclk";
+ status = "disabled";
+ };
+
i2s0: i2s at 1011a000 {
compatible = "rockchip,rk3188-i2s", "rockchip,rk3066-i2s";
reg = <0x1011a000 0x2000>;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3] ARM: Drop fixed 200 Hz timer requirement from Samsung platforms
From: Krzysztof Kozlowski @ 2016-11-23 17:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479467712-5218-1-git-send-email-krzk@kernel.org>
On Fri, Nov 18, 2016 at 01:15:12PM +0200, Krzysztof Kozlowski wrote:
> All Samsung platforms, including the Exynos, are selecting HZ_FIXED with
> 200 Hz. Unfortunately in case of multiplatform image this affects also
> other platforms when Exynos is enabled.
>
> This looks like an very old legacy code, dating back to initial
> upstreaming of S3C24xx. Probably it was required for s3c24xx timer
> driver, which was removed in commit ad38bdd15d5b ("ARM: SAMSUNG: Remove
> unused plat-samsung/time.c").
>
> Since then, this fixed 200 Hz spread everywhere, including out-of-tree
> Samsung kernels (SoC vendor's and Tizen's). I believe this choice
> was rather an effect of coincidence instead of conscious choice.
>
> On S3C24xx, the PWM counter is only 16 bit wide, and with the
> typical 12MHz input clock that overflows every 5.5ms. This works
> with HZ=200 or higher but not with HZ=100 which needs a 10ms
> interval between ticks. On Later chips (S3C64xx, S5P and EXYNOS),
> the counter is 32 bits and does not have this problem.
>
> The new samsung_pwm_timer driver solves the problem by scaling the input
> clock by a factor of 50 on S3C24xx, which makes it less accurate but
> allows HZ=100 as well as CONFIG_NO_HZ with fewer wakeups.
>
> Few perf mem and sched tests on Odroid XU3 board (Exynos5422, 4x Cortex
> A7, 4x Cortex A15) show no regressions when switching from 200 Hz to
> other values.
>
> Reported-by: Lee Jones <lee.jones@linaro.org>
> [Dropping of 200_HZ from S3C/S5P was suggested by Arnd]
> Reported-by: Arnd Bergmann <arnd@arndb.de>
> Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
> Cc: Kukjin Kim <kgene@kernel.org>
> [Tested on Exynos5800]
> Tested-by: Javier Martinez Canillas <javier@osg.samsung.com>
> Acked-by: Kukjin Kim <kgene@kernel.org>
> [Tested on S3C2440]
> Tested-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
>
> ---
>
> Changes since v2:
> 1. Extend message.
> 2. Add Kukjin's ack.
> 3. Add Sylwester's tested-by.
>
> Changes since v1:
> 1. Add Javier's tested-by.
> 2. Drop HZ_FIXED also from ARCH_S5PV210 and ARCH_S3C24XX after Arnd
> suggestions and analysis.
> ---
> arch/arm/Kconfig | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
Applied,
Krzysztof
^ permalink raw reply
* [PATCH v2 1/5] ARM: memory: da8xx-ddrctl: new driver
From: Frank Rowand @ 2016-11-23 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <b668871c-2b54-0a2f-0d68-afaa50e17e63@ti.com>
On 11/22/16 21:55, Sekhar Nori wrote:
> On Tuesday 22 November 2016 11:51 PM, Frank Rowand wrote:
>> Please note that the compatible property might contain several strings, not just
>> a single string.
>
> So I guess the best thing to do is to use
> of_property_read_string_index() and print the sting at index 0.
>
> Thanks,
> Sekhar
If you want to print just one compatible value, you could use that method.
To give all of the information needed to understand the problem, the error
message would need to include all of the strings contained in the compatible
property and all of the .board values in the da8xx_ddrctl_board_confs[] array
(currently only one entry, but coded to allow additional entries in the
future).
It is hard to justify an error message that complex.
I would just print an error that no match was found.
-Frank
^ permalink raw reply
* [PATCH V9 11/11] ARM64/PCI: Support for ACPI based PCI host controller
From: Bjorn Helgaas @ 2016-11-23 18:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <edf72769-e9c8-4617-8dc4-8f3d05a678e7@semihalf.com>
On Wed, Nov 23, 2016 at 12:21:03PM +0100, Tomasz Nowicki wrote:
> Hi Bjorn,
>
> On 23.11.2016 00:13, Bjorn Helgaas wrote:
> >Hi Tomasz,
> >
> >On Fri, Jun 10, 2016 at 09:55:19PM +0200, Tomasz Nowicki wrote:
> >>Implement pci_acpi_scan_root and other arch-specific call so that ARM64
> >>can start using ACPI to setup and enumerate PCI buses.
> >>
> >>Prior to buses enumeration the pci_acpi_scan_root() implementation looks
> >>for configuration space start address (obtained through ACPI _CBA method or
> >>MCFG interface). If succeed, it uses ECAM library to create new mapping.
> >>Then it attaches generic ECAM ops (pci_generic_ecam_ops) which are used
> >>for accessing configuration space later on.
> >>...
> >
> >>+static struct acpi_pci_root_ops acpi_pci_root_ops = {
> >>+ .release_info = pci_acpi_generic_release_info,
> >>+};
> >>+
> >>+/* Interface called from ACPI code to setup PCI host controller */
> >> struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
> >> {
> >>- /* TODO: Should be revisited when implementing PCI on ACPI */
> >>- return NULL;
> >>+ int node = acpi_get_node(root->device->handle);
> >>+ struct acpi_pci_generic_root_info *ri;
> >>+ struct pci_bus *bus, *child;
> >>+
> >>+ ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node);
> >>+ if (!ri)
> >>+ return NULL;
> >>+
> >>+ ri->cfg = pci_acpi_setup_ecam_mapping(root);
> >>+ if (!ri->cfg) {
> >>+ kfree(ri);
> >>+ return NULL;
> >>+ }
> >>+
> >>+ acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops;
> >
> >This has already been merged, but this isn't right, is it? We're
> >writing a host controller-specific pointer into the single system-wide
> >acpi_pci_root_ops, then passing it on to acpi_pci_root_create().
> >
> >Today, I think ri->cfg->ops->pci_ops is always &pci_generic_ecam_ops,
> >from this path:
> >
> > ri->cfg = pci_acpi_setup_ecam_mapping
> > cfg = pci_ecam_create(..., &pci_generic_ecam_ops)
> > cfg = kzalloc(...)
> > cfg->ops = ops # &pci_generic_ecam_ops
> >
> >But we're about to merge the ECAM quirks series, which will mean it
> >may not be &pci_generic_ecam_ops. Even apart from the ECAM quirks, we
> >should avoid this pattern of putting device-specific info in a single
> >shared structure because it's too difficult to verify that it's
> >correct.
> >
>
> Well spotted. I agree, we need to fix this. How about this:
> diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
> index fb439c7..31c0e1c 100644
> --- a/arch/arm64/kernel/pci.c
> +++ b/arch/arm64/kernel/pci.c
> @@ -152,33 +152,35 @@ static void
> pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
>
> ri = container_of(ci, struct acpi_pci_generic_root_info, common);
> pci_ecam_free(ri->cfg);
> + kfree(ci->ops);
> kfree(ri);
> }
>
> -static struct acpi_pci_root_ops acpi_pci_root_ops = {
> - .release_info = pci_acpi_generic_release_info,
> -};
> -
> /* Interface called from ACPI code to setup PCI host controller */
> struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
> {
> int node = acpi_get_node(root->device->handle);
> struct acpi_pci_generic_root_info *ri;
> struct pci_bus *bus, *child;
> + struct acpi_pci_root_ops *root_ops;
>
> ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node);
> if (!ri)
> return NULL;
>
> + root_ops = kzalloc_node(sizeof(*root_ops), GFP_KERNEL, node);
> + if (!root_ops)
> + return NULL;
> +
> ri->cfg = pci_acpi_setup_ecam_mapping(root);
> if (!ri->cfg) {
> kfree(ri);
> + kfree(root_ops);
> return NULL;
> }
>
> - acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops;
> - bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common,
> - ri->cfg);
> + root_ops->release_info = pci_acpi_generic_release_info;
> + root_ops->pci_ops = &ri->cfg->ops->pci_ops;
> + bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg);
> if (!bus)
> return NULL;
>
> Of course, this should be the part of ECAM quirks core patches.
>
> The other option we have is to remove "struct pci_ops *pci_ops;"
> from acpi_pci_root_ops structure and pass struct pci_ops as an extra
> argument to acpi_pci_root_create(). What do you think?
I think your patch above is fine and avoids the need to change the x86 and
ia64 code. Would you mind packaging this up with a changelog and
signed-off-by? I can take care of putting it in the ECAM series.
Thanks,
Bjorn
^ permalink raw reply
* [PATCH v2 1/5] ARM: memory: da8xx-ddrctl: new driver
From: Frank Rowand @ 2016-11-23 18:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5835DC2D.5080606@gmail.com>
On 11/23/16 10:13, Frank Rowand wrote:
> On 11/22/16 21:55, Sekhar Nori wrote:
>> On Tuesday 22 November 2016 11:51 PM, Frank Rowand wrote:
>>> Please note that the compatible property might contain several strings, not just
>>> a single string.
>>
>> So I guess the best thing to do is to use
>> of_property_read_string_index() and print the sting at index 0.
>>
>> Thanks,
>> Sekhar
>
> If you want to print just one compatible value, you could use that method.
>
> To give all of the information needed to understand the problem, the error
> message would need to include all of the strings contained in the compatible
> property and all of the .board values in the da8xx_ddrctl_board_confs[] array
> (currently only one entry, but coded to allow additional entries in the
> future).
>
> It is hard to justify an error message that complex.
>
> I would just print an error that no match was found.
>
> -Frank
I just needed to read some more emails. I see this approach was taken
in the "[PATCH v4 0/2] da8xx: fix section mismatch in new drivers"
series.
-Frank
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox