* [PATCHv12] ARM: dts: Add support for the cpuimx35 board from Eukrea and its baseboard.
From: Shawn Guo @ 2014-01-28 8:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389803532-8516-1-git-send-email-denis@eukrea.com>
On Wed, Jan 15, 2014 at 05:32:12PM +0100, Denis Carikli wrote:
> diff --git a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
> new file mode 100644
> index 0000000..303f789
> --- /dev/null
> +++ b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
> @@ -0,0 +1,59 @@
> +/*
> + * Copyright 2013 Eukr?a Electromatique <denis@eukrea.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.
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include "imx35.dtsi"
> +
> +/ {
> + model = "Eukrea CPUIMX35";
> + compatible = "eukrea,cpuimx35", "fsl,imx35";
> +
> + memory {
> + reg = <0x80000000 0x8000000>; /* 128M */
> + };
> +};
> +
> +&fec {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_fec>;
> + status = "okay";
> +};
> +
> +&i2c1 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_i2c1>;
> + status = "okay";
> +
> + pcf8563 at 51 {
> + compatible = "nxp,pcf8563";
> + reg = <0x51>;
> + };
> +};
> +
> +&iomuxc {
> + imx35-eukrea {
> + pinctrl_fec: fecgrp {
> + fsl,pins = <MX35_FEC_PINGRP1>;
> + };
> +
> + pinctrl_i2c1: i2c1grp {
> + fsl,pins = <MX35_I2C1_PINGRP1>;
> + };
You have these two pingrp in imx35-eukrea-cpuimx35.dtsi ...
> + };
> +};
> +
> +&nfc {
> + nand-bus-width = <8>;
> + nand-ecc-mode = "hw";
> + nand-on-flash-bbt;
> + status = "okay";
> +};
> diff --git a/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts b/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts
> new file mode 100644
> index 0000000..23f6fe1
> --- /dev/null
> +++ b/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts
> @@ -0,0 +1,137 @@
> +/*
> + * Copyright 2013 Eukr?a Electromatique <denis@eukrea.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.
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/input/input.h>
> +#include "imx35-eukrea-cpuimx35.dtsi"
... imx35-eukrea-cpuimx35.dtsi is being included here ...
> +
> +/ {
> + model = "Eukrea CPUIMX35";
> + compatible = "eukrea,mbimxsd35-baseboard", "eukrea,cpuimx35", "fsl,imx35";
> +
> + gpio_keys {
> + compatible = "gpio-keys";
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_bp1>;
> +
> + bp1 {
> + label = "BP1";
> + gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
> + linux,code = <BTN_MISC>;
> + gpio-key,wakeup;
> + linux,input-type = <1>;
> + };
> + };
> +
> + leds {
> + compatible = "gpio-leds";
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_led1>;
> +
> + led1 {
> + label = "led1";
> + gpios = <&gpio3 29 GPIO_ACTIVE_LOW>;
> + linux,default-trigger = "heartbeat";
> + };
> + };
> +};
> +
> +&audmux {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_audmux>;
> + status = "okay";
> +};
> +
> +&esdhc1 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_esdhc1>;
> + cd-gpios = <&gpio3 24>;
> + status = "okay";
> +};
> +
> +&i2c1 {
> + tlv320aic23: codec at 1a {
> + compatible = "ti,tlv320aic23";
> + reg = <0x1a>;
> + };
> +};
> +
> +&iomuxc {
> + imx35-eukrea {
> + pinctrl_audmux: audmuxgrp {
> + fsl,pins = <MX35_AUDMUX_PINGRP1>;
> + };
> +
> + pinctrl_bp1: bp1grp {
> + fsl,pins = <MX35_PAD_LD19__GPIO3_25 0x80000000>;
> + };
> +
> + pinctrl_esdhc1: esdhc1grp {
> + fsl,pins = <
> + MX35_ESDHC1_PINGRP1
> + MX35_PAD_LD18__GPIO3_24 0x80000000 /* CD */
> + >;
> + };
> +
> + pinctrl_fec: fecgrp {
> + fsl,pins = <MX35_FEC_PINGRP1>;
> + };
> +
> + pinctrl_i2c1: i2c1grp {
> + fsl,pins = <MX35_I2C1_PINGRP1>;
> + };
... why do you need to have them again?
I spotted this when rebasing this patch on pingrp removal series, and
just dropped them from imx35-eukrea-mbimxsd35-baseboard.dts. Let me
know if I did get it right.
Shawn
> +
> + pinctrl_led1: led1grp {
> + fsl,pins = <MX35_PAD_LD23__GPIO3_29 0x80000000>;
> + };
> +
> + pinctrl_reg_lcd_3v3: reg-lcd-3v3 {
> + fsl,pins = <MX35_PAD_D3_CLS__GPIO1_4 0x80000000>;
> + };
> +
> + pinctrl_uart1: uart1grp {
> + fsl,pins = <
> + MX35_UART1_PINGRP1
> + MX35_UART1_RTSCTS_PINGRP1
> + >;
> + };
> +
> + pinctrl_uart2: uart2grp {
> + fsl,pins = <
> + MX35_UART2_PINGRP1
> + MX35_UART2_RTSCTS_PINGRP1
> + >;
> + };
> + };
> +};
> +
> +&ssi1 {
> + fsl,mode = "i2s-slave";
> + status = "okay";
> +};
> +
> +&uart1 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_uart1>;
> + fsl,uart-has-rtscts;
> + status = "okay";
> +};
> +
> +&uart2 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_uart2>;
> + fsl,uart-has-rtscts;
> + status = "okay";
> +};
> --
> 1.7.9.5
>
^ permalink raw reply
* imx-drm: screen flickering
From: Christian Gmeiner @ 2014-01-28 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAH9NwWfjsGbLiuY_cDOrUUQFpeSumVVkr-kV2BRAKtsRgGaYGw@mail.gmail.com>
2014-01-28 Christian Gmeiner <christian.gmeiner@gmail.com>:
> 2014-01-28 Christian Gmeiner <christian.gmeiner@gmail.com>:
>> Hi all.
>>
>> From time to time it happens that my LVDS display is flickering (look
>> at scroll bar in the video).
>> https://drive.google.com/file/d/0B_fznDimUHVubWtvVFlMTkdBbUU/edit?usp=sharing
>>
>> I really want to find the root cause of it, but I do not know where to
>> start. I can trigger this
>> sometimes after xscreensever "blanks" the screen and the screensafer
>> gets disabled
>> via user input.
>>
>> Any hints?
>
> I forgot to add some details. I am using a 3.12.4 kernel with some a
> some patches (dts, ..). As root filesystem
> I am using debian 7 and this is how my xorg.conf looks like:
>
> root at OT:/sys/kernel/debug# cat /etc/X11/xorg.conf
> #
> # DO NOT TOUCH - AUTOGENERATED FILE
> #
>
> Section "Device"
> Identifier "Card0"
> Driver "modesetting"
>
> EndSection
>
> Section "InputClass"
> Identifier "keyboard layout"
> MatchIsKeyboard "on"
> MatchDevicePath "/dev/input/event*"
> Driver "evdev"
> Option "XkbLayout" "us"
> EndSection
>
>
> xscreensaver makes use of DPMS. So I think that the the problem could
> be related to DPMS somehow.
>
I can trigger this with:
xset dpms force off; sleep 2; xset dpms force on
I need to execute this command less then 6 times to get the flickering.
greets
--
Christian Gmeiner, MSc
^ permalink raw reply
* imx-drm: screen flickering
From: Christian Gmeiner @ 2014-01-28 8:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAH9NwWe673znThNPWRvOCyAU2o7M-oouHD7+1tyRcmWTeJ8YFw@mail.gmail.com>
2014-01-28 Christian Gmeiner <christian.gmeiner@gmail.com>:
> Hi all.
>
> From time to time it happens that my LVDS display is flickering (look
> at scroll bar in the video).
> https://drive.google.com/file/d/0B_fznDimUHVubWtvVFlMTkdBbUU/edit?usp=sharing
>
> I really want to find the root cause of it, but I do not know where to
> start. I can trigger this
> sometimes after xscreensever "blanks" the screen and the screensafer
> gets disabled
> via user input.
>
> Any hints?
I forgot to add some details. I am using a 3.12.4 kernel with some a
some patches (dts, ..). As root filesystem
I am using debian 7 and this is how my xorg.conf looks like:
root at OT:/sys/kernel/debug# cat /etc/X11/xorg.conf
#
# DO NOT TOUCH - AUTOGENERATED FILE
#
Section "Device"
Identifier "Card0"
Driver "modesetting"
EndSection
Section "InputClass"
Identifier "keyboard layout"
MatchIsKeyboard "on"
MatchDevicePath "/dev/input/event*"
Driver "evdev"
Option "XkbLayout" "us"
EndSection
xscreensaver makes use of DPMS. So I think that the the problem could
be related to DPMS somehow.
greets
--
Christian Gmeiner, MSc
^ permalink raw reply
* [PATCH RFC v2 2/2] Documentation: arm: define DT C-states bindings
From: Vincent Guittot @ 2014-01-28 8:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140124175806.GC23274@e102568-lin.cambridge.arm.com>
On 24 January 2014 18:58, Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> wrote:
> Hi Vincent,
>
> On Fri, Jan 24, 2014 at 08:40:40AM +0000, Vincent Guittot wrote:
>
> [...]
>
>> Hi Lorenzo,
>>
>> Sorry for the late reply,
>>
>>
>> > I had an idea. To simplify things, I think that one possibility is to
>> > add a parameter to the power domain specifier (platform specific, see
>> > Tomasz bindings):
>>
>> We can't use a simple boolean state (on/off) for defining the
>> powerdomain state associated to a c-state so your proposal of being
>> able to add a parameter that will define the power domain state is
>> interesting.
>>
>> >
>> > Documentation/devicetree/bindings/power/power_domain.txt
>> >
>> > http://lists.infradead.org/pipermail/linux-arm-kernel/2014-January/224928.html
>> >
>> > to represent, when that state is entered the behavior of the power
>> > controller (ie cache RAM retention or cache shutdown or in general any
>> > substate within a power domain). Since it is platform specific, and since
>> > we are able to link caches to the power domain, the power controller will
>> > actually define what happens to the cache when that state is entered
>> > (basically we use the power domain specifier additional parameter to define
>> > a "substate" in that power domain e.g.:
>> >
>> > Example:
>> >
>> > foo_power_controller {
>> > [...]
>> > /*
>> > * first cell is register index, second one is the state index
>> > * that in turn implies the state behavior - eg cache lost or
>> > * retained
>> > */
>> > #power-domain-cells = <2>;
>> > };
>> >
>> > l1-cache {
>> > [...]
>> > /*
>> > * syntax: power-domains = list of power domain specifiers
>> > <[&power_domain_phandle register-index state],[&power_domain_phandle register-index state]>;
>> > The syntax is defined by the power controller du jour
>> > as described by Tomasz bindings
>> > */
>> > power-domains =<&foo_power_controller 0 0 &foo_power_controller 0 1>;
>>
>> Normally, power-domains describes a list of power domain specifiers
>> that are necessary for the l1-cache to at least retain its state so
>> i'm not sure understand your example above
>
>>
>> If we take the example of system that support running, retention and
>> powerdown state described as state 0, 1 and 2 for the power domain, i
>> would have set the l1-cache like:
>> power-domains =<&foo_power_controller 0 1>;
>>
>> for saying that the state is retained up to state 1
>>
>> Please look below, i have modified the rest of your example accordingly
>>
>> >
>> > }:
>> >
>> > and then
>> >
>> > state0 {
>> > index = <2>;
>> > compatible = "arm,cpu-power-state";
>> > latency = <...>;
>> > /*
>> > * This means that when the state is entered, the power
>> > * controller should use register index 0 and state 0,
>> > * whose meaning is power controller specific. Since we
>> > * know all components affected (for every component
>> > * we declare its power domain(s) and states so we
>> > * know what components are affected by the state entry.
>> > * Given the cache node above and this phandle, the state
>> > * implies that the cache is retained, register index == 0 state == 0
>> > /*
>> > power-domain =<&foo_power_controller 0 0>;
>>
>> for retention state we need to set the power domain in state 1
>> power-domain =<&foo_power_controller 0 1>;
>>
>> > };
>> >
>> > state1 {
>> > index = <3>;
>> > compatible = "arm,cpu-power-state";
>> > latency = <...>;
>> > /*
>> > * This means that when the state is entered, the power
>> > * controller should use register index 0 and state 1,
>> > * whose meaning is power controller specific. Since we
>> > * know all components affected (for every component
>> > * we declare its power domain(s) and states so we
>> > * know what components are affected by the state entry.
>> > * Given the cache node above and this phandle, the state
>> > * implies that the cache is lost, register index == 0 state == 1
>> > /*
>> > power-domain =<&foo_power_controller 0 1>;
>>
>> for power down mode, we need to set thge power domain in state 2
>> power-domain =<&foo_power_controller 0 2>;
>
> Ok, what I meant was not what you got, but your approach looks sensible
> too. What I do not like is that the power-domain specifier is power
sorry for the misconception of your example
> controller specific (that was true even for my example). In theory
> we can achieve something identical by forcing every component in a power
> domain to specify the max C-state index that allows it to retain its
I'm not sure that we should force a component to set an opaque (for
the component) max c-state. The device should describe its power
domain requirements and the correlation of the latter with the
description of the c-state binding should be enough to deduct the max
c-state.
> state (through a specific property). Same logic to your example applies.
> Nice thing is that we do not change the power domain specifiers, bad thing
> is that it adds two properties to each device (c-state index and
> power-domain-specifier - but we can make it hierarchical so that device
> nodes can inherit the maximum operating C-state by inheriting the value
> from a parent node providing a common value).
>
> In my example the third parameter was just a number that the power
> controller would decode (eg 0 = cache retained, 1 = cache lost)
> according to its implementation, it was not a "state index". The
> power controller would know what to do with eg a cache component (that
> declares to be in that power domain) when a C-state with that power
> domain specifier was entered.
>
> Not very different from what you are saying, let's get to the nub:
>
> - Either we define it in a platform specific way through the power
> domain specifier
> - Or we force a max-c-state-supported property for every device,
> possibly hierarchical
As explained above, adding a max-cstate property for a device that
only know the power-domain is not a good thing IMHO.
Vincent
>
> Thoughts ?
>
> Thank you !
> Lorenzo
>
^ permalink raw reply
* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
From: Lukasz Majewski @ 2014-01-28 8:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAJuA9ah1vsgpD04QhM5RApkCe9xcvpPkLvdwzgadKGWvngAt+g@mail.gmail.com>
Hi Thomas, Mike
> Hi Mike,
>
> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette
> <mturquette@linaro.org> wrote:
> > Quoting Thomas Abraham (2014-01-18 04:10:51)
> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >>
> >> On some platforms such as the Samsung Exynos, changing the
> >> frequency of the CPU clock requires changing the frequency of the
> >> PLL that is supplying the CPU clock. To change the frequency of
> >> the PLL, the CPU clock is temporarily reparented to another parent
> >> clock.
> >>
> >> The clock frequency of this temporary parent clock could be much
> >> higher than the clock frequency of the PLL at the time of
> >> reparenting. Due to the temporary increase in the CPU clock speed,
> >> the CPU (and any other components in the CPU clock domain such as
> >> dividers, mux, etc.) have to to be operated at a higher voltage
> >> level, called the safe voltage level. This patch adds optional
> >> support to temporarily switch to a safe voltage level during CPU
> >> frequency transitions.
> >>
> >> Cc: Shawn Guo <shawn.guo@linaro.org>
> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >
> > I'm not a fan of this change. This corner case should be abstracted
> > away somehow. I had talked to Chander Kayshap previously about
> > handling voltage changes in clock notifier callbacks, which then
> > renders any voltage change as a trivial part of the clock rate
> > transition. That means that this "safe voltage" thing could be
> > handled automagically without any additional code in the CPUfreq
> > driver.
> >
> > There are two nice ways to do this with the clock framework. First
> > is explicit re-parenting with voltage scaling done in the clock
> > rate-change notifiers:
> >
> > clk_set_parent(cpu_clk, temp_parent);
> > /* implicit voltage scaling to "safe voltage" happens above */
> > clk_set_rate(pll, some_rate);
> > clk_set_parent(cpu_clk, pll);
> > /* implicit voltage scaling to nominal OPP voltage happens above */
> >
I must agree with Mike here. In my opinion the above approach is more
compliant with CCF (as I've pointed it out in my other comment - the
cpu_clk has more than one parent and we could switch between them when
needed).
> > The above sequence would require a separate exnyos CPUfreq driver,
> > due to the added clk_set_parent logic.
> >
> > The second way to do this is to abstract the clk re-muxing logic out
> > into the clk driver, which would allow cpufreq-cpu0 to be used for
> > the exynos chips.
>
> This is the approach this patch series takes (patch 2/7). The clock
> re-muxing logic is handled by a clock driver code. The difference from
> what you suggested is that the safe voltage (that may be optionally)
> required before doing the re-muxing is handled here in cpufreq-cpu0
> driver.
>
> The safe voltage setup can be done in the notifier as you suggested.
If the clk_set_parent() approach is not suitable, then cannot we
consider using the one from highbank-cpufreq.c?
Here we have cpufreq-cpu0.c which sets voltage of the cpu_clk.
In the highbank-cpufreq.c there are clock notifiers to change the
voltage.
Cannot Exynos reuse such approach? Why shall we pollute cpufreq-cpu0.c
with another solution?
> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
> this feature if required. Also, if done here, the regulator handling
> is localized in this driver which otherwise would need to be handled
> in two places, cpufreq-cpu0 driver and the clock notifier.
I think that there is a logical distinction between setting voltage for
cpufreq-cpu0 related clock and increasing voltage of reparented clock.
The former fits naturally to cpufreq-cpu0, when the latter seems like
some corner case (as Mike pointed out) for Exynos.
>
> So I tend to prefer the approach in this patch but I am willing to
> consider any suggestions.
Thomas, what do you think about highbank-cpufreq.c approach (with
using clock notifiers)?
Do you think, that it is feasible to reuse it with Exynos?
> Shawn, it would be helpful if you could let
> us know your thoughts on this. I am almost done with testing the v3 of
> this series and want to post it so if there are any objections to the
> changes in this patch, please let me know.
>
> Thanks,
> Thomas.
>
> >
> > I'm more a fan of explicitly listing the Exact Steps for the cpu opp
> > transition in a separate exynos-specific CPUfreq driver, but that's
> > probably an unpopular view.
> >
> > Regards,
> > Mike
> >
> >> ---
> >> .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt | 7 ++++
> >> drivers/cpufreq/cpufreq-cpu0.c | 37
> >> +++++++++++++++++-- 2 files changed, 40 insertions(+), 4
> >> deletions(-)
> >>
> >> diff --git
> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt index
> >> f055515..37453ab 100644 ---
> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++
> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@
> >> -19,6 +19,12 @@ Optional properties:
> >> - cooling-min-level:
> >> - cooling-max-level:
> >> Please refer to
> >> Documentation/devicetree/bindings/thermal/thermal.txt. +-
> >> safe-opp: Certain platforms require that during a opp transition,
> >> + a system should not go below a particular opp level. For such
> >> systems,
> >> + this property specifies the minimum opp to be maintained during
> >> the
> >> + opp transitions. The safe-opp value is a tuple with first
> >> element
> >> + representing the safe frequency and the second element
> >> representing the
> >> + safe voltage.
> >>
> >> Examples:
> >>
> >> @@ -36,6 +42,7 @@ cpus {
> >> 396000 950000
> >> 198000 850000
> >> >;
> >> + safe-opp = <396000 950000>
> >> clock-latency = <61036>; /* two CLK32 periods */
> >> #cooling-cells = <2>;
> >> cooling-min-level = <0>;
> >> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
> >> b/drivers/cpufreq/cpufreq-cpu0.c index 0c12ffc..075d3d1 100644
> >> --- a/drivers/cpufreq/cpufreq-cpu0.c
> >> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> >> @@ -27,6 +27,8 @@
> >>
> >> static unsigned int transition_latency;
> >> static unsigned int voltage_tolerance; /* in percentage */
> >> +static unsigned long safe_frequency;
> >> +static unsigned long safe_voltage;
> >>
> >> static struct device *cpu_dev;
> >> static struct clk *cpu_clk;
> >> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct
> >> cpufreq_policy *policy, unsigned int index) volt_old =
> >> regulator_get_voltage(cpu_reg); }
> >>
> >> - pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> >> + pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
> >> old_freq / 1000, volt_old ? volt_old / 1000 : -1,
> >> new_freq / 1000, volt ? volt / 1000 : -1);
> >>
> >> /* scaling up? scale voltage before frequency */
> >> - if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
> >> + if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
> >> + new_freq >= safe_frequency) {
> >> ret = regulator_set_voltage_tol(cpu_reg, volt,
> >> tol); if (ret) {
> >> pr_err("failed to scale voltage up: %d\n",
> >> ret); return ret;
> >> }
> >> + } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
> >> + /*
> >> + * the scaled up voltage level for the new_freq is
> >> lower
> >> + * than the safe voltage level. so set safe_voltage
> >> + * as the intermediate voltage level and revert it
> >> + * back after the frequency has been changed.
> >> + */
> >> + ret = regulator_set_voltage_tol(cpu_reg,
> >> safe_voltage, tol);
> >> + if (ret) {
> >> + pr_err("failed to set safe voltage: %d\n",
> >> ret);
> >> + return ret;
> >> + }
> >> }
> >>
> >> ret = clk_set_rate(cpu_clk, freq_exact);
> >> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct
> >> cpufreq_policy *policy, unsigned int index) }
> >>
> >> /* scaling down? scale voltage after frequency */
> >> - if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
> >> + if (!IS_ERR(cpu_reg) &&
> >> + (new_freq < old_freq || new_freq <
> >> safe_frequency)) { ret = regulator_set_voltage_tol(cpu_reg, volt,
> >> tol); if (ret) {
> >> pr_err("failed to scale voltage down:
> >> %d\n", ret); @@ -116,6 +132,8 @@ static struct cpufreq_driver
> >> cpu0_cpufreq_driver = {
> >>
> >> static int cpu0_cpufreq_probe(struct platform_device *pdev)
> >> {
> >> + const struct property *prop;
> >> + struct dev_pm_opp *opp;
> >> struct device_node *np;
> >> int ret;
> >>
> >> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct
> >> platform_device *pdev) goto out_put_node;
> >> }
> >>
> >> + prop = of_find_property(np, "safe-opp", NULL);
> >> + if (prop) {
> >> + if (prop->value && (prop->length / sizeof(u32)) ==
> >> 2) {
> >> + const __be32 *val;
> >> + val = prop->value;
> >> + safe_frequency = be32_to_cpup(val++);
> >> + safe_voltage = be32_to_cpup(val);
> >> + } else {
> >> + pr_err("invalid safe-opp level
> >> specified\n");
> >> + }
> >> + }
> >> +
> >> of_property_read_u32(np, "voltage-tolerance",
> >> &voltage_tolerance);
> >>
> >> if (of_property_read_u32(np, "clock-latency",
> >> &transition_latency)) transition_latency = CPUFREQ_ETERNAL;
> >>
> >> if (!IS_ERR(cpu_reg)) {
> >> - struct dev_pm_opp *opp;
> >> unsigned long min_uV, max_uV;
> >> int i;
> >>
> >> --
> >> 1.6.6.rc2
> >>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
^ permalink raw reply
* imx-drm: screen flickering
From: Christian Gmeiner @ 2014-01-28 8:11 UTC (permalink / raw)
To: linux-arm-kernel
Hi all.
>From time to time it happens that my LVDS display is flickering (look
at scroll bar in the video).
https://drive.google.com/file/d/0B_fznDimUHVubWtvVFlMTkdBbUU/edit?usp=sharing
I really want to find the root cause of it, but I do not know where to
start. I can trigger this
sometimes after xscreensever "blanks" the screen and the screensafer
gets disabled
via user input.
Any hints?
--
Christian Gmeiner, MSc
^ permalink raw reply
* [PATCH RFC v3 4/8] ASoC: davinci-evm: HDMI audio support for TDA998x trough McASP I2S bus
From: Jyri Sarha @ 2014-01-28 7:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140127204910.GB11841@sirena.org.uk>
On 01/27/2014 10:49 PM, Mark Brown wrote:
> On Mon, Jan 27, 2014 at 05:37:53PM +0200, Jyri Sarha wrote:
>> Add machine driver support for BeagleBone-Black and other boards with
>> tilcdc support and NXP TDA998X HDMI transmitter connected to McASP
>> port in I2S mode. McASP produces the bit clock for the i2s bus from
>> the masted clock by a simple divider and the available sample rates
>
> I have to say I agree with Lars' comments about where the code to set
> the constraints is here - I don't doubt that these limitations are valid
> but it would be better to factor them into the relevant chip drivers so
> that other systems with similar limitations can be handled correctly
> too.
>
Ok, I'll push them into mcasp driver then.
Thanks,
Jyri
^ permalink raw reply
* [PATCH] pinctrl: single: add low powr mode support
From: Chao Xie @ 2014-01-28 7:20 UTC (permalink / raw)
To: linux-arm-kernel
From: Chao Xie <chao.xie@marvell.com>
For some silicons, the pin configuration register can control
the output of the pin when the pad including the pin enter
low power mode.
For example, the pin can be "Drive 1", "Drive 0", "Float" when
the pad including the pin enter low power mode.
It is very useful when you want to control the power leakeage
when the SOC enter low power mode, and can save more power for
the low power mode.
Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt | 7 +++++++
drivers/pinctrl/pinctrl-single.c | 3 +++
2 files changed, 10 insertions(+)
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
index bc0dfdf..66dcaa9 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
@@ -63,6 +63,13 @@ Optional properties:
/* input, enable bits, disable bits, mask */
pinctrl-single,input-schmitt-enable = <0x30 0x40 0 0x70>;
+- pinctrl-single,low-power-mode : array of value that are used to configure
+ low power mode of this pin. For some silicons, the low power mode will
+ control the output of the pin when the pad including the pin enter low
+ power mode.
+ /* low power mode value, mask */
+ pinctrl-single,low-power-mode = <0x288 0x388>;
+
- pinctrl-single,gpio-range : list of value that are used to configure a GPIO
range. They're value of subnode phandle, pin base in pinctrl device, pin
number in this range, GPIO function value of this GPIO range.
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 41f1cfe..18ed6b6 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -661,6 +661,7 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
break;
case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
+ case PIN_CONFIG_LOW_POWER_MODE:
default:
*config = data;
break;
@@ -698,6 +699,7 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
case PIN_CONFIG_INPUT_SCHMITT:
case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
+ case PIN_CONFIG_LOW_POWER_MODE:
shift = ffs(func->conf[i].mask) - 1;
data &= ~func->conf[i].mask;
data |= (arg << shift) & func->conf[i].mask;
@@ -1100,6 +1102,7 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
{ "pinctrl-single,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, },
{ "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
{ "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
+ { "pinctrl-single,low-power-mode", PIN_CONFIG_LOW_POWER_MODE, },
};
struct pcs_conf_type prop4[] = {
{ "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
--
1.8.3.2
^ permalink raw reply related
* [PATCH V2] arm64: add DSB after icache flush in __flush_icache_all()
From: Vinayak Kale @ 2014-01-28 7:06 UTC (permalink / raw)
To: linux-arm-kernel
Add DSB after icache flush. It's needed to complete the cache maintenance
operation. The function __flush_icache_all() is used only for user space
mappings and an ISB is not required because of an exception return before
executing user instructions. An exception return would behave like an ISB.
This patch also uses 'memory' clobber for flush operation instruction to
prevent instruction re-ordering by compiler.
Signed-off-by: Vinayak Kale <vkale@apm.com>
---
V2: - Add more desciption in the commit message as suggested by Catalin & Will
- Use 'memory' clobber for flush instruction as suggested by Will
arch/arm64/include/asm/cacheflush.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index fea9ee3..bd30f42 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -115,7 +115,8 @@ extern void flush_dcache_page(struct page *);
static inline void __flush_icache_all(void)
{
- asm("ic ialluis");
+ asm volatile("ic ialluis" : : : "memory");
+ dsb();
}
#define flush_dcache_mmap_lock(mapping) \
--
1.8.2.1
^ permalink raw reply related
* [Patch v3 2/2] dmaengine: qcom_bam_dma: Add device tree binding
From: Andy Gross @ 2014-01-28 6:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390890471-14882-1-git-send-email-agross@codeaurora.org>
Add device tree binding support for the QCOM BAM DMA driver.
Signed-off-by: Andy Gross <agross@codeaurora.org>
---
.../devicetree/bindings/dma/qcom_bam_dma.txt | 52 ++++++++++++++++++++
1 file changed, 52 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/qcom_bam_dma.txt
diff --git a/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt b/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt
new file mode 100644
index 0000000..53fd10a
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt
@@ -0,0 +1,52 @@
+QCOM BAM DMA controller
+
+Required properties:
+- compatible: Must be "qcom,bam-v1.4.0" for MSM8974 V1
+ Must be "qcom,bam-v1.4.1" for MSM8974 V2
+- reg: Address range for DMA registers
+- interrupts: single interrupt for this controller
+- #dma-cells: must be <2>
+- clocks: required clock
+- clock-names: name of clock
+- qcom,ee : indicates the active Execution Environment identifier (0-7)
+
+Example:
+
+ uart-bam: dma at f9984000 = {
+ compatible = "qcom,bam-v1.4.1";
+ reg = <0xf9984000 0x15000>;
+ interrupts = <0 94 0>;
+ clocks = <&gcc GCC_BAM_DMA_AHB_CLK>;
+ clock-names = "bam_clk";
+ #dma-cells = <2>;
+ qcom,ee = <0>;
+ };
+
+Client:
+Required properties:
+- dmas: List of dma channel requests
+- dma-names: Names of aforementioned requested channels
+
+Clients must use the format described in the dma.txt file, using a three cell
+specifier for each channel.
+
+The three cells in order are:
+ 1. A phandle pointing to the DMA controller
+ 2. The channel number
+ 3. Direction of the fixed unidirectional channel
+ 0 - Memory to Device
+ 1 - Device to Memory
+ 2 - Device to Device
+
+Example:
+ serial at f991e000 {
+ compatible = "qcom,msm-uart";
+ reg = <0xf991e000 0x1000>
+ <0xf9944000 0x19000>;
+ interrupts = <0 108 0>;
+ clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
+
+ dmas = <&uart-bam 0 1>, <&uart-bam 1 0>;
+ dma-names = "rx", "tx";
+ };
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply related
* [Patch v3 1/2] dmaengine: add Qualcomm BAM dma driver
From: Andy Gross @ 2014-01-28 6:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390890471-14882-1-git-send-email-agross@codeaurora.org>
Add the DMA engine driver for the QCOM Bus Access Manager (BAM) DMA controller
found in the MSM 8x74 platforms.
Each BAM DMA device is associated with a specific on-chip peripheral. Each
channel provides a uni-directional data transfer engine that is capable of
transferring data between the peripheral and system memory (System mode), or
between two peripherals (BAM2BAM).
The initial release of this driver only supports slave transfers between
peripherals and system memory.
Signed-off-by: Andy Gross <agross@codeaurora.org>
---
drivers/dma/Kconfig | 9 +
drivers/dma/Makefile | 1 +
drivers/dma/qcom_bam_dma.c | 1083 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1093 insertions(+)
create mode 100644 drivers/dma/qcom_bam_dma.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index c10eb89..1b2f6cf 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -386,4 +386,13 @@ config DMATEST
config DMA_ENGINE_RAID
bool
+config QCOM_BAM_DMA
+ tristate "QCOM BAM DMA support"
+ depends on ARCH_MSM_DT || (COMPILE_TEST && OF && ARM)
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ ---help---
+ Enable support for the QCOM BAM DMA controller. This controller
+ provides DMA capabilities for a variety of on-chip devices.
+
endif
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 0ce2da9..7ef950a 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
obj-$(CONFIG_TI_CPPI41) += cppi41.o
obj-$(CONFIG_K3_DMA) += k3dma.o
+obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o
diff --git a/drivers/dma/qcom_bam_dma.c b/drivers/dma/qcom_bam_dma.c
new file mode 100644
index 0000000..3574d2a
--- /dev/null
+++ b/drivers/dma/qcom_bam_dma.c
@@ -0,0 +1,1083 @@
+/*
+ * QCOM BAM DMA engine driver
+ *
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * QCOM BAM DMA blocks are distributed amongst a number of the on-chip
+ * peripherals on the MSM 8x74. The configuration of the channels are dependent
+ * on the way they are hard wired to that specific peripheral. The peripheral
+ * device tree entries specify the configuration of each channel.
+ *
+ * The DMA controller requires the use of external memory for storage of the
+ * hardware descriptors for each channel. The descriptor FIFO is accessed as a
+ * circular buffer and operations are managed according to the offset within the
+ * FIFO. After pipe/channel reset, all of the pipe registers and internal state
+ * are back to defaults.
+ *
+ * During DMA operations, we write descriptors to the FIFO, being careful to
+ * handle wrapping and then write the last FIFO offset to that channel's
+ * P_EVNT_REG register to kick off the transaction. The P_SW_OFSTS register
+ * indicates the current FIFO offset that is being processed, so there is some
+ * indication of where the hardware is currently working.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_dma.h>
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+
+#include "dmaengine.h"
+#include "virt-dma.h"
+
+enum bam_channel_dir {
+ BAM_PIPE_CONSUMER = 0, /* channel reads from data-fifo or memory */
+ BAM_PIPE_PRODUCER, /* channel writes to data-fifo or memory */
+};
+
+struct bam_desc_hw {
+ u32 addr; /* Buffer physical address */
+ u16 size; /* Buffer size in bytes */
+ u16 flags;
+};
+
+#define DESC_FLAG_INT BIT(15)
+#define DESC_FLAG_EOT BIT(14)
+#define DESC_FLAG_EOB BIT(13)
+
+struct bam_async_desc {
+ struct virt_dma_desc vd;
+
+ u32 num_desc;
+ u32 xfer_len;
+ struct bam_desc_hw *curr_desc;
+
+ enum bam_channel_dir dir;
+ size_t length;
+ struct bam_desc_hw desc[0];
+};
+
+#define BAM_CTRL 0x0000
+#define BAM_REVISION 0x0004
+#define BAM_SW_REVISION 0x0080
+#define BAM_NUM_PIPES 0x003C
+#define BAM_TIMER 0x0040
+#define BAM_TIMER_CTRL 0x0044
+#define BAM_DESC_CNT_TRSHLD 0x0008
+#define BAM_IRQ_SRCS 0x000C
+#define BAM_IRQ_SRCS_MSK 0x0010
+#define BAM_IRQ_SRCS_UNMASKED 0x0030
+#define BAM_IRQ_STTS 0x0014
+#define BAM_IRQ_CLR 0x0018
+#define BAM_IRQ_EN 0x001C
+#define BAM_CNFG_BITS 0x007C
+#define BAM_IRQ_SRCS_EE(pipe) (0x0800 + ((pipe) * 0x80))
+#define BAM_IRQ_SRCS_MSK_EE(pipe) (0x0804 + ((pipe) * 0x80))
+#define BAM_P_CTRL(pipe) (0x1000 + ((pipe) * 0x1000))
+#define BAM_P_RST(pipe) (0x1004 + ((pipe) * 0x1000))
+#define BAM_P_HALT(pipe) (0x1008 + ((pipe) * 0x1000))
+#define BAM_P_IRQ_STTS(pipe) (0x1010 + ((pipe) * 0x1000))
+#define BAM_P_IRQ_CLR(pipe) (0x1014 + ((pipe) * 0x1000))
+#define BAM_P_IRQ_EN(pipe) (0x1018 + ((pipe) * 0x1000))
+#define BAM_P_EVNT_DEST_ADDR(pipe) (0x182C + ((pipe) * 0x1000))
+#define BAM_P_EVNT_REG(pipe) (0x1818 + ((pipe) * 0x1000))
+#define BAM_P_SW_OFSTS(pipe) (0x1800 + ((pipe) * 0x1000))
+#define BAM_P_DATA_FIFO_ADDR(pipe) (0x1824 + ((pipe) * 0x1000))
+#define BAM_P_DESC_FIFO_ADDR(pipe) (0x181C + ((pipe) * 0x1000))
+#define BAM_P_EVNT_TRSHLD(pipe) (0x1828 + ((pipe) * 0x1000))
+#define BAM_P_FIFO_SIZES(pipe) (0x1820 + ((pipe) * 0x1000))
+
+/* BAM CTRL */
+#define BAM_SW_RST BIT(0)
+#define BAM_EN BIT(1)
+#define BAM_EN_ACCUM BIT(4)
+#define BAM_TESTBUS_SEL_SHIFT 5
+#define BAM_TESTBUS_SEL_MASK 0x3F
+#define BAM_DESC_CACHE_SEL_SHIFT 13
+#define BAM_DESC_CACHE_SEL_MASK 0x3
+#define BAM_CACHED_DESC_STORE BIT(15)
+#define IBC_DISABLE BIT(16)
+
+/* BAM REVISION */
+#define REVISION_SHIFT 0
+#define REVISION_MASK 0xFF
+#define NUM_EES_SHIFT 8
+#define NUM_EES_MASK 0xF
+#define CE_BUFFER_SIZE BIT(13)
+#define AXI_ACTIVE BIT(14)
+#define USE_VMIDMT BIT(15)
+#define SECURED BIT(16)
+#define BAM_HAS_NO_BYPASS BIT(17)
+#define HIGH_FREQUENCY_BAM BIT(18)
+#define INACTIV_TMRS_EXST BIT(19)
+#define NUM_INACTIV_TMRS BIT(20)
+#define DESC_CACHE_DEPTH_SHIFT 21
+#define DESC_CACHE_DEPTH_1 (0 << DESC_CACHE_DEPTH_SHIFT)
+#define DESC_CACHE_DEPTH_2 (1 << DESC_CACHE_DEPTH_SHIFT)
+#define DESC_CACHE_DEPTH_3 (2 << DESC_CACHE_DEPTH_SHIFT)
+#define DESC_CACHE_DEPTH_4 (3 << DESC_CACHE_DEPTH_SHIFT)
+#define CMD_DESC_EN BIT(23)
+#define INACTIV_TMR_BASE_SHIFT 24
+#define INACTIV_TMR_BASE_MASK 0xFF
+
+/* BAM NUM PIPES */
+#define BAM_NUM_PIPES_SHIFT 0
+#define BAM_NUM_PIPES_MASK 0xFF
+#define PERIPH_NON_PIPE_GRP_SHIFT 16
+#define PERIPH_NON_PIP_GRP_MASK 0xFF
+#define BAM_NON_PIPE_GRP_SHIFT 24
+#define BAM_NON_PIPE_GRP_MASK 0xFF
+
+/* BAM CNFG BITS */
+#define BAM_PIPE_CNFG BIT(2)
+#define BAM_FULL_PIPE BIT(11)
+#define BAM_NO_EXT_P_RST BIT(12)
+#define BAM_IBC_DISABLE BIT(13)
+#define BAM_SB_CLK_REQ BIT(14)
+#define BAM_PSM_CSW_REQ BIT(15)
+#define BAM_PSM_P_RES BIT(16)
+#define BAM_AU_P_RES BIT(17)
+#define BAM_SI_P_RES BIT(18)
+#define BAM_WB_P_RES BIT(19)
+#define BAM_WB_BLK_CSW BIT(20)
+#define BAM_WB_CSW_ACK_IDL BIT(21)
+#define BAM_WB_RETR_SVPNT BIT(22)
+#define BAM_WB_DSC_AVL_P_RST BIT(23)
+#define BAM_REG_P_EN BIT(24)
+#define BAM_PSM_P_HD_DATA BIT(25)
+#define BAM_AU_ACCUMED BIT(26)
+#define BAM_CMD_ENABLE BIT(27)
+
+#define BAM_CNFG_BITS_DEFAULT (BAM_PIPE_CNFG | \
+ BAM_NO_EXT_P_RST | \
+ BAM_IBC_DISABLE | \
+ BAM_SB_CLK_REQ | \
+ BAM_PSM_CSW_REQ | \
+ BAM_PSM_P_RES | \
+ BAM_AU_P_RES | \
+ BAM_SI_P_RES | \
+ BAM_WB_P_RES | \
+ BAM_WB_BLK_CSW | \
+ BAM_WB_CSW_ACK_IDL | \
+ BAM_WB_RETR_SVPNT | \
+ BAM_WB_DSC_AVL_P_RST | \
+ BAM_REG_P_EN | \
+ BAM_PSM_P_HD_DATA | \
+ BAM_AU_ACCUMED | \
+ BAM_CMD_ENABLE)
+
+/* PIPE CTRL */
+#define P_EN BIT(1)
+#define P_DIRECTION BIT(3)
+#define P_SYS_STRM BIT(4)
+#define P_SYS_MODE BIT(5)
+#define P_AUTO_EOB BIT(6)
+#define P_AUTO_EOB_SEL_SHIFT 7
+#define P_AUTO_EOB_SEL_512 (0 << P_AUTO_EOB_SEL_SHIFT)
+#define P_AUTO_EOB_SEL_256 (1 << P_AUTO_EOB_SEL_SHIFT)
+#define P_AUTO_EOB_SEL_128 (2 << P_AUTO_EOB_SEL_SHIFT)
+#define P_AUTO_EOB_SEL_64 (3 << P_AUTO_EOB_SEL_SHIFT)
+#define P_PREFETCH_LIMIT_SHIFT 9
+#define P_PREFETCH_LIMIT_32 (0 << P_PREFETCH_LIMIT_SHIFT)
+#define P_PREFETCH_LIMIT_16 (1 << P_PREFETCH_LIMIT_SHIFT)
+#define P_PREFETCH_LIMIT_4 (2 << P_PREFETCH_LIMIT_SHIFT)
+#define P_WRITE_NWD BIT(11)
+#define P_LOCK_GROUP_SHIFT 16
+#define P_LOCK_GROUP_MASK 0x1F
+
+/* BAM_DESC_CNT_TRSHLD */
+#define CNT_TRSHLD 0xffff
+#define DEFAULT_CNT_THRSHLD 0x4
+
+/* BAM_IRQ_SRCS */
+#define BAM_IRQ BIT(31)
+#define P_IRQ 0x7fffffff
+
+/* BAM_IRQ_SRCS_MSK */
+#define BAM_IRQ_MSK BAM_IRQ
+#define P_IRQ_MSK P_IRQ
+
+/* BAM_IRQ_STTS */
+#define BAM_TIMER_IRQ BIT(4)
+#define BAM_EMPTY_IRQ BIT(3)
+#define BAM_ERROR_IRQ BIT(2)
+#define BAM_HRESP_ERR_IRQ BIT(1)
+
+/* BAM_IRQ_CLR */
+#define BAM_TIMER_CLR BIT(4)
+#define BAM_EMPTY_CLR BIT(3)
+#define BAM_ERROR_CLR BIT(2)
+#define BAM_HRESP_ERR_CLR BIT(1)
+
+/* BAM_IRQ_EN */
+#define BAM_TIMER_EN BIT(4)
+#define BAM_EMPTY_EN BIT(3)
+#define BAM_ERROR_EN BIT(2)
+#define BAM_HRESP_ERR_EN BIT(1)
+
+/* BAM_P_IRQ_EN */
+#define P_PRCSD_DESC_EN BIT(0)
+#define P_TIMER_EN BIT(1)
+#define P_WAKE_EN BIT(2)
+#define P_OUT_OF_DESC_EN BIT(3)
+#define P_ERR_EN BIT(4)
+#define P_TRNSFR_END_EN BIT(5)
+#define P_DEFAULT_IRQS_EN (P_PRCSD_DESC_EN | P_ERR_EN | P_TRNSFR_END_EN)
+
+/* BAM_P_SW_OFSTS */
+#define P_SW_OFSTS_MASK 0xffff
+
+#define BAM_DESC_FIFO_SIZE SZ_32K
+#define MAX_DESCRIPTORS (BAM_DESC_FIFO_SIZE / sizeof(struct bam_desc_hw) - 1)
+#define BAM_MAX_DATA_SIZE (SZ_32K - 8)
+
+struct bam_chan {
+ struct virt_dma_chan vc;
+
+ struct bam_device *bdev;
+
+ /* configuration from device tree */
+ u32 id;
+ u32 ee;
+
+ struct bam_async_desc *curr_txd; /* current running dma */
+
+ /* runtime configuration */
+ struct dma_slave_config slave;
+
+ /* fifo storage */
+ struct bam_desc_hw *fifo_virt;
+ dma_addr_t fifo_phys;
+
+ /* fifo markers */
+ unsigned short head; /* start of active descriptor entries */
+ unsigned short tail; /* end of active descriptor entries */
+
+ unsigned int initialized; /* is the channel hw initialized? */
+ unsigned int paused; /* is the channel paused? */
+
+ struct list_head node;
+};
+
+static inline struct bam_chan *to_bam_chan(struct dma_chan *common)
+{
+ return container_of(common, struct bam_chan, vc.chan);
+}
+
+struct bam_device {
+ void __iomem *regs;
+ struct device *dev;
+ struct dma_device common;
+ struct device_dma_parameters dma_parms;
+ struct bam_chan *channels;
+ u32 num_channels;
+
+ /* execution environment ID, from DT */
+ u32 ee;
+
+ struct clk *bamclk;
+
+ /* dma start transaction tasklet */
+ struct tasklet_struct task;
+};
+
+/**
+ * bam_reset_channel - Reset individual BAM DMA channel
+ * @bchan: bam channel
+ *
+ * This function resets a specific BAM channel
+ */
+static void bam_reset_channel(struct bam_chan *bchan)
+{
+ struct bam_device *bdev = bchan->bdev;
+
+ /* reset channel */
+ writel_relaxed(1, bdev->regs + BAM_P_RST(bchan->id));
+ writel_relaxed(0, bdev->regs + BAM_P_RST(bchan->id));
+
+ /* don't allow reorder of the channel reset */
+ wmb();
+
+ /* make sure hw is initialized when channel is used the first time */
+ bchan->initialized = 0;
+}
+
+/**
+ * bam_chan_init_hw - Initialize channel hardware
+ * @bchan: bam channel
+ *
+ * This function resets and initializes the BAM channel
+ */
+static void bam_chan_init_hw(struct bam_chan *bchan)
+{
+ struct bam_device *bdev = bchan->bdev;
+ u32 val;
+
+ /* Reset the channel to clear internal state of the FIFO */
+ bam_reset_channel(bchan);
+
+ /*
+ * write out 8 byte aligned address. We have enough space for this
+ * because we allocated 1 more descriptor (8 bytes) than we can use
+ */
+ writel_relaxed(ALIGN(bchan->fifo_phys, sizeof(struct bam_desc_hw)),
+ bdev->regs + BAM_P_DESC_FIFO_ADDR(bchan->id));
+ writel_relaxed(BAM_DESC_FIFO_SIZE, bdev->regs +
+ BAM_P_FIFO_SIZES(bchan->id));
+
+ /* unmask and enable interrupts for defined EE, bam and error irqs */
+ writel_relaxed(BAM_IRQ_MSK, bdev->regs + BAM_IRQ_SRCS_EE(bdev->ee));
+
+ /* enable the per pipe interrupts, enable EOT, ERR, and INT irqs */
+ writel_relaxed(P_DEFAULT_IRQS_EN, bdev->regs + BAM_P_IRQ_EN(bchan->id));
+
+ /* unmask the specific pipe and EE combo */
+ val = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+ val |= BIT(bchan->id);
+ writel_relaxed(val, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+
+ /* set fixed direction and mode, then enable channel */
+ val = P_EN | P_SYS_MODE;
+ if (bchan->slave.direction == DMA_DEV_TO_MEM)
+ val |= P_DIRECTION;
+
+ /* make sure the other stores occur before enabling channel */
+ wmb();
+ writel_relaxed(val, bdev->regs + BAM_P_CTRL(bchan->id));
+
+ bchan->initialized = 1;
+
+ /* init FIFO pointers */
+ bchan->head = 0;
+ bchan->tail = 0;
+}
+
+/**
+ * bam_alloc_chan - Allocate channel resources for DMA channel.
+ * @chan: specified channel
+ *
+ * This function allocates the FIFO descriptor memory
+ */
+static int bam_alloc_chan(struct dma_chan *chan)
+{
+ struct bam_chan *bchan = to_bam_chan(chan);
+ struct bam_device *bdev = bchan->bdev;
+
+ /* allocate FIFO descriptor space, but only if necessary */
+ if (!bchan->fifo_virt) {
+ bchan->fifo_virt = dma_alloc_writecombine(bdev->dev,
+ BAM_DESC_FIFO_SIZE, &bchan->fifo_phys,
+ GFP_KERNEL);
+
+ if (!bchan->fifo_virt) {
+ dev_err(bdev->dev, "Failed to allocate desc fifo\n");
+ return -ENOMEM;
+ }
+ }
+
+ return BAM_DESC_FIFO_SIZE;
+}
+
+/**
+ * bam_free_chan - Frees dma resources associated with specific channel
+ * @chan: specified channel
+ *
+ * Free the allocated fifo descriptor memory and channel resources
+ *
+ */
+static void bam_free_chan(struct dma_chan *chan)
+{
+ struct bam_chan *bchan = to_bam_chan(chan);
+ struct bam_device *bdev = bchan->bdev;
+ u32 val;
+
+ vchan_free_chan_resources(to_virt_chan(chan));
+
+ if (bchan->curr_txd) {
+ dev_err(bchan->bdev->dev, "Cannot free busy channel\n");
+ return;
+ }
+
+ bam_reset_channel(bchan);
+
+ dma_free_writecombine(bdev->dev, BAM_DESC_FIFO_SIZE, bchan->fifo_virt,
+ bchan->fifo_phys);
+ bchan->fifo_virt = NULL;
+
+ /* mask irq for pipe/channel */
+ val = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+ val &= ~BIT(bchan->id);
+ writel_relaxed(val, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+
+ /* disable irq */
+ writel_relaxed(0, bdev->regs + BAM_P_IRQ_EN(bchan->id));
+}
+
+/**
+ * bam_slave_config - set slave configuration for channel
+ * @chan: dma channel
+ * @cfg: slave configuration
+ *
+ * Sets slave configuration for channel
+ * Only allow setting direction once. BAM channels are unidirectional
+ * and the direction is set in hardware.
+ *
+ */
+static void bam_slave_config(struct bam_chan *bchan,
+ struct dma_slave_config *cfg)
+{
+ struct bam_device *bdev = bchan->bdev;
+ u32 maxburst;
+
+ if (bchan->slave.direction == DMA_DEV_TO_MEM)
+ maxburst = bchan->slave.src_maxburst = cfg->src_maxburst;
+ else
+ maxburst = bchan->slave.dst_maxburst = cfg->dst_maxburst;
+
+ /* set desc threshold */
+ writel_relaxed(maxburst, bdev->regs + BAM_DESC_CNT_TRSHLD);
+}
+
+/**
+ * bam_prep_slave_sg - Prep slave sg transaction
+ *
+ * @chan: dma channel
+ * @sgl: scatter gather list
+ * @sg_len: length of sg
+ * @direction: DMA transfer direction
+ * @flags: DMA flags
+ * @context: transfer context (unused)
+ */
+static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
+ struct scatterlist *sgl, unsigned int sg_len,
+ enum dma_transfer_direction direction, unsigned long flags,
+ void *context)
+{
+ struct bam_chan *bchan = to_bam_chan(chan);
+ struct bam_device *bdev = bchan->bdev;
+ struct bam_async_desc *async_desc;
+ struct scatterlist *sg;
+ u32 i;
+ struct bam_desc_hw *desc;
+
+
+ if (!is_slave_direction(direction)) {
+ dev_err(bdev->dev, "invalid dma direction\n");
+ return NULL;
+ }
+
+ /* direction has to match pipe configuration from the slave config */
+ if (direction != bchan->slave.direction) {
+ dev_err(bdev->dev,
+ "direction does not match configuration\n");
+ return NULL;
+ }
+
+ /* allocate enough room to accomodate the number of entries */
+ async_desc = kzalloc(sizeof(*async_desc) +
+ (sg_len * sizeof(struct bam_desc_hw)), GFP_NOWAIT);
+
+ if (!async_desc) {
+ dev_err(bdev->dev, "failed to allocate async descriptor\n");
+ goto err_out;
+ }
+
+ async_desc->num_desc = sg_len;
+ async_desc->curr_desc = async_desc->desc;
+ async_desc->dir = (direction == DMA_DEV_TO_MEM) ? BAM_PIPE_PRODUCER :
+ BAM_PIPE_CONSUMER;
+
+ /* fill in descriptors, align hw descriptor to 8 bytes */
+ desc = async_desc->desc;
+ for_each_sg(sgl, sg, sg_len, i) {
+ if (sg_dma_len(sg) > BAM_MAX_DATA_SIZE) {
+ dev_err(bdev->dev, "segment exceeds max size\n");
+ goto err_out;
+ }
+
+ desc->addr = sg_dma_address(sg);
+ desc->size = sg_dma_len(sg);
+ async_desc->length += sg_dma_len(sg);
+ desc++;
+ }
+
+ return vchan_tx_prep(&bchan->vc, &async_desc->vd, flags);
+
+err_out:
+ kfree(async_desc);
+ return NULL;
+}
+
+/**
+ * bam_dma_terminate_all - terminate all transactions
+ * @chan: dma channel
+ *
+ * Dequeues and frees all non-active transactions
+ * No callbacks are done
+ *
+ */
+static void bam_dma_terminate_all(struct dma_chan *chan)
+{
+ struct bam_chan *bchan = to_bam_chan(chan);
+
+ /* remove all transactions that are queued but not active */
+ vchan_free_chan_resources(&bchan->vc);
+}
+
+/**
+ * bam_control - DMA device control
+ * @chan: dma channel
+ * @cmd: control cmd
+ * @arg: cmd argument
+ *
+ * Perform DMA control command
+ *
+ */
+static int bam_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct bam_chan *bchan = to_bam_chan(chan);
+ struct bam_device *bdev = bchan->bdev;
+ int ret = 0;
+ unsigned long flag;
+
+ switch (cmd) {
+ case DMA_PAUSE:
+ spin_lock_irqsave(&bchan->vc.lock, flag);
+ writel_relaxed(1, bdev->regs + BAM_P_HALT(bchan->id));
+ bchan->paused = 1;
+ spin_unlock_irqrestore(&bchan->vc.lock, flag);
+ break;
+ case DMA_RESUME:
+ spin_lock_irqsave(&bchan->vc.lock, flag);
+ writel_relaxed(0, bdev->regs + BAM_P_HALT(bchan->id));
+ bchan->paused = 0;
+ spin_unlock_irqrestore(&bchan->vc.lock, flag);
+ break;
+ case DMA_TERMINATE_ALL:
+ spin_lock_irqsave(&bchan->vc.lock, flag);
+ bam_dma_terminate_all(chan);
+ spin_unlock_irqrestore(&bchan->vc.lock, flag);
+ break;
+ case DMA_SLAVE_CONFIG:
+ bam_slave_config(bchan, (struct dma_slave_config *)arg);
+ break;
+ default:
+ ret = -ENXIO;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * process_channel_irqs - processes the channel interrupts
+ * @bdev: bam controller
+ *
+ * This function processes the channel interrupts
+ *
+ */
+static u32 process_channel_irqs(struct bam_device *bdev)
+{
+ u32 i, srcs, pipe_stts;
+ unsigned long flags;
+ struct bam_async_desc *async_desc;
+
+
+ srcs = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_EE(bdev->ee));
+
+ /* return early if no pipe/channel interrupts are present */
+ if (!(srcs & P_IRQ))
+ return srcs;
+
+ for (i = 0; i < bdev->num_channels; i++) {
+ struct bam_chan *bchan = &bdev->channels[i];
+ if (srcs & BIT(i)) {
+ /* clear pipe irq */
+ pipe_stts = readl_relaxed(bdev->regs +
+ BAM_P_IRQ_STTS(i));
+
+ writel_relaxed(pipe_stts, bdev->regs +
+ BAM_P_IRQ_CLR(i));
+
+ spin_lock_irqsave(&bchan->vc.lock, flags);
+ async_desc = bchan->curr_txd;
+
+ if (async_desc) {
+ async_desc->num_desc -= async_desc->xfer_len;
+ async_desc->curr_desc += async_desc->xfer_len;
+ bchan->curr_txd = NULL;
+
+ /* manage FIFO */
+ bchan->head += async_desc->xfer_len;
+ bchan->head %= MAX_DESCRIPTORS;
+
+ /*
+ * if complete, process cookie. Otherwise
+ * push back to front of desc_issued so that
+ * it gets restarted by the tasklet
+ */
+ if (!async_desc->num_desc)
+ vchan_cookie_complete(&async_desc->vd);
+ else
+ list_add(&async_desc->vd.node,
+ &bchan->vc.desc_issued);
+ }
+
+ spin_unlock_irqrestore(&bchan->vc.lock, flags);
+ }
+ }
+
+ return srcs;
+}
+
+/**
+ * bam_dma_irq - irq handler for bam controller
+ * @irq: IRQ of interrupt
+ * @data: callback data
+ *
+ * IRQ handler for the bam controller
+ */
+static irqreturn_t bam_dma_irq(int irq, void *data)
+{
+ struct bam_device *bdev = data;
+ u32 clr_mask = 0, srcs = 0;
+
+ srcs |= process_channel_irqs(bdev);
+
+ /* kick off tasklet to start next dma transfer */
+ if (srcs & P_IRQ)
+ tasklet_schedule(&bdev->task);
+
+ if (srcs & BAM_IRQ)
+ clr_mask = readl_relaxed(bdev->regs + BAM_IRQ_STTS);
+
+ /* don't allow reorder of the various accesses to the BAM registers */
+ mb();
+
+ writel_relaxed(clr_mask, bdev->regs + BAM_IRQ_CLR);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * bam_tx_status - returns status of transaction
+ * @chan: dma channel
+ * @cookie: transaction cookie
+ * @txstate: DMA transaction state
+ *
+ * Return status of dma transaction
+ */
+static enum dma_status bam_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct bam_chan *bchan = to_bam_chan(chan);
+ struct virt_dma_desc *vd;
+ int ret;
+ size_t residue = 0;
+ unsigned int i;
+ unsigned long flags;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret == DMA_COMPLETE)
+ return ret;
+
+ if (!txstate)
+ return bchan->paused ? DMA_PAUSED : ret;
+
+ spin_lock_irqsave(&bchan->vc.lock, flags);
+ vd = vchan_find_desc(&bchan->vc, cookie);
+ if (vd)
+ residue = container_of(vd, struct bam_async_desc, vd)->length;
+ else if (bchan->curr_txd && bchan->curr_txd->vd.tx.cookie == cookie)
+ for (i = 0; i < bchan->curr_txd->num_desc; i++)
+ residue += bchan->curr_txd->curr_desc[i].size;
+
+ spin_unlock_irqrestore(&bchan->vc.lock, flags);
+
+ dma_set_residue(txstate, residue);
+
+ if (ret == DMA_IN_PROGRESS && bchan->paused)
+ ret = DMA_PAUSED;
+
+ return ret;
+}
+
+/**
+ * bam_start_dma - start next transaction
+ * @bchan - bam dma channel
+ *
+ * Note: must hold bam dma channel vc.lock
+ */
+static void bam_start_dma(struct bam_chan *bchan)
+{
+ struct virt_dma_desc *vd = vchan_next_desc(&bchan->vc);
+ struct bam_device *bdev = bchan->bdev;
+ struct bam_async_desc *async_desc;
+ struct bam_desc_hw *desc;
+ struct bam_desc_hw *fifo = PTR_ALIGN(bchan->fifo_virt,
+ sizeof(struct bam_desc_hw));
+
+ if (!vd)
+ return;
+
+ /* on first use, initialize the channel hardware */
+ if (!bchan->initialized)
+ bam_chan_init_hw(bchan);
+
+ list_del(&vd->node);
+
+ async_desc = container_of(vd, struct bam_async_desc, vd);
+ bchan->curr_txd = async_desc;
+
+ desc = bchan->curr_txd->curr_desc;
+
+ if (async_desc->num_desc > MAX_DESCRIPTORS)
+ async_desc->xfer_len = MAX_DESCRIPTORS;
+ else
+ async_desc->xfer_len = async_desc->num_desc;
+
+ /* set INT on last descriptor */
+ desc[async_desc->xfer_len - 1].flags |= DESC_FLAG_INT;
+
+ if (bchan->tail + async_desc->xfer_len > MAX_DESCRIPTORS) {
+ u32 partial = MAX_DESCRIPTORS - bchan->tail;
+
+ memcpy(&fifo[bchan->tail], desc,
+ partial * sizeof(struct bam_desc_hw));
+ memcpy(fifo, &desc[partial], (async_desc->xfer_len - partial) *
+ sizeof(struct bam_desc_hw));
+ } else {
+ memcpy(&fifo[bchan->tail], desc,
+ async_desc->xfer_len * sizeof(struct bam_desc_hw));
+ }
+
+ bchan->tail += async_desc->xfer_len;
+ bchan->tail %= MAX_DESCRIPTORS;
+
+ /* ensure descriptor writes and dma start not reordered */
+ wmb();
+ writel_relaxed(bchan->tail * sizeof(struct bam_desc_hw),
+ bdev->regs + BAM_P_EVNT_REG(bchan->id));
+}
+
+/**
+ * dma_tasklet - DMA IRQ tasklet
+ * @data: tasklet argument (bam controller structure)
+ *
+ * Sets up next DMA operation and then processes all completed transactions
+ */
+static void dma_tasklet(unsigned long data)
+{
+ struct bam_device *bdev = (struct bam_device *)data;
+ struct bam_chan *bchan;
+ unsigned long flags;
+ unsigned int i;
+
+ /* go through the channels and kick off transactions */
+ for (i = 0; i < bdev->num_channels; i++) {
+ bchan = &bdev->channels[i];
+ spin_lock_irqsave(&bchan->vc.lock, flags);
+
+ if (!list_empty(&bchan->vc.desc_issued) && !bchan->curr_txd)
+ bam_start_dma(bchan);
+ spin_unlock_irqrestore(&bchan->vc.lock, flags);
+ }
+}
+
+/**
+ * bam_issue_pending - starts pending transactions
+ * @chan: dma channel
+ *
+ * Calls tasklet directly which in turn starts any pending transactions
+ */
+static void bam_issue_pending(struct dma_chan *chan)
+{
+ struct bam_chan *bchan = to_bam_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bchan->vc.lock, flags);
+
+ /* if work pending and idle, start a transaction */
+ if (vchan_issue_pending(&bchan->vc) && !bchan->curr_txd)
+ bam_start_dma(bchan);
+
+ spin_unlock_irqrestore(&bchan->vc.lock, flags);
+}
+
+/**
+ * bam_dma_free_desc - free descriptor memory
+ * @vd: virtual descriptor
+ *
+ */
+static void bam_dma_free_desc(struct virt_dma_desc *vd)
+{
+ struct bam_async_desc *async_desc = container_of(vd,
+ struct bam_async_desc, vd);
+
+ kfree(async_desc);
+}
+
+static struct dma_chan *bam_dma_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *of)
+{
+ struct bam_device *bdev = container_of(of->of_dma_data,
+ struct bam_device, common);
+ struct dma_chan *chan;
+ struct bam_chan *bchan;
+ unsigned int request;
+
+ if (dma_spec->args_count != 2)
+ return NULL;
+
+ request = dma_spec->args[0];
+ if (request >= bdev->num_channels)
+ return NULL;
+
+ chan = dma_get_slave_channel(&(bdev->channels[request].vc.chan));
+ if (chan) {
+ bchan = to_bam_chan(chan);
+
+ /* set fixed direction */
+ switch (dma_spec->args[1]) {
+ case 0:
+ bchan->slave.direction = DMA_MEM_TO_DEV;
+ break;
+ case 1:
+ bchan->slave.direction = DMA_DEV_TO_MEM;
+ break;
+ case 2:
+ bchan->slave.direction = DMA_DEV_TO_DEV;
+ break;
+ default:
+ dev_err(bdev->dev, "Invalid dma direction\n");
+ dma_release_channel(chan);
+ return NULL;
+ }
+ }
+
+ return chan;
+}
+
+/**
+ * bam_init
+ * @bdev: bam device
+ *
+ * Initialization helper for global bam registers
+ */
+static int bam_init(struct bam_device *bdev)
+{
+ u32 val;
+
+ /* read revision and configuration information */
+ val = readl_relaxed(bdev->regs + BAM_REVISION) & NUM_EES_MASK;
+
+ /* check that configured EE is within range */
+ if (bdev->ee >= val)
+ return -EINVAL;
+
+ val = readl_relaxed(bdev->regs + BAM_NUM_PIPES);
+ bdev->num_channels = val & BAM_NUM_PIPES_MASK;
+
+ /* s/w reset bam */
+ /* after reset all pipes are disabled and idle */
+ val = readl_relaxed(bdev->regs + BAM_CTRL);
+ val |= BAM_SW_RST;
+ writel_relaxed(val, bdev->regs + BAM_CTRL);
+ val &= ~BAM_SW_RST;
+ writel_relaxed(val, bdev->regs + BAM_CTRL);
+
+ /* make sure previous stores are visible before enabling BAM */
+ wmb();
+
+ /* enable bam */
+ val |= BAM_EN;
+ writel_relaxed(val, bdev->regs + BAM_CTRL);
+
+ /* set descriptor threshhold, start with 4 bytes */
+ writel_relaxed(DEFAULT_CNT_THRSHLD, bdev->regs + BAM_DESC_CNT_TRSHLD);
+
+ /* Enable default set of h/w workarounds, ie all except BAM_FULL_PIPE */
+ writel_relaxed(BAM_CNFG_BITS_DEFAULT, bdev->regs + BAM_CNFG_BITS);
+
+ /* enable irqs for errors */
+ writel_relaxed(BAM_ERROR_EN | BAM_HRESP_ERR_EN,
+ bdev->regs + BAM_IRQ_EN);
+
+ return 0;
+}
+
+static void bam_channel_init(struct bam_device *bdev, struct bam_chan *bchan,
+ u32 index)
+{
+ bchan->id = index;
+ bchan->bdev = bdev;
+
+ vchan_init(&bchan->vc, &bdev->common);
+ bchan->vc.desc_free = bam_dma_free_desc;
+
+ bam_reset_channel(bchan);
+}
+
+static int bam_dma_probe(struct platform_device *pdev)
+{
+ struct bam_device *bdev;
+ struct resource *iores;
+ int ret, i, irq;
+
+ bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
+ if (!bdev)
+ return -ENOMEM;
+
+ bdev->dev = &pdev->dev;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ bdev->regs = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(bdev->regs))
+ return PTR_ERR(bdev->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ bdev->bamclk = devm_clk_get(bdev->dev, "bam_clk");
+ if (IS_ERR(bdev->bamclk))
+ return PTR_ERR(bdev->bamclk);
+
+ ret = clk_prepare_enable(bdev->bamclk);
+ if (ret) {
+ dev_err(bdev->dev, "failed to prepare/enable clock");
+ return ret;
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &bdev->ee);
+ if (ret) {
+ dev_err(bdev->dev, "EE unspecified\n");
+ return ret;
+ }
+
+ ret = bam_init(bdev);
+ if (ret)
+ return ret;
+
+ tasklet_init(&bdev->task, dma_tasklet, (unsigned long)bdev);
+
+ bdev->channels = devm_kcalloc(bdev->dev, bdev->num_channels,
+ sizeof(*bdev->channels), GFP_KERNEL);
+
+ if (!bdev->channels) {
+ ret = -ENOMEM;
+ goto err_disable_clk;
+ }
+
+ /* allocate and initialize channels */
+ INIT_LIST_HEAD(&bdev->common.channels);
+
+ for (i = 0; i < bdev->num_channels; i++)
+ bam_channel_init(bdev, &bdev->channels[i], i);
+
+ ret = devm_request_irq(bdev->dev, irq, bam_dma_irq, IRQF_TRIGGER_HIGH,
+ "bam_dma", bdev);
+ if (ret)
+ goto err_disable_clk;
+
+ /* set max dma segment size */
+ bdev->common.dev = bdev->dev;
+ bdev->common.dev->dma_parms = &bdev->dma_parms;
+ ret = dma_set_max_seg_size(bdev->common.dev, BAM_MAX_DATA_SIZE);
+ if (ret) {
+ dev_err(bdev->dev, "cannot set maximum segment size\n");
+ goto err_disable_clk;
+ }
+
+ platform_set_drvdata(pdev, bdev);
+
+ /* set capabilities */
+ dma_cap_zero(bdev->common.cap_mask);
+ dma_cap_set(DMA_SLAVE, bdev->common.cap_mask);
+
+ /* initialize dmaengine apis */
+ bdev->common.device_alloc_chan_resources = bam_alloc_chan;
+ bdev->common.device_free_chan_resources = bam_free_chan;
+ bdev->common.device_prep_slave_sg = bam_prep_slave_sg;
+ bdev->common.device_control = bam_control;
+ bdev->common.device_issue_pending = bam_issue_pending;
+ bdev->common.device_tx_status = bam_tx_status;
+ bdev->common.dev = bdev->dev;
+
+ ret = dma_async_device_register(&bdev->common);
+ if (ret) {
+ dev_err(bdev->dev, "failed to register dma async device\n");
+ goto err_disable_clk;
+ }
+
+ ret = of_dma_controller_register(pdev->dev.of_node, bam_dma_xlate,
+ &bdev->common);
+ if (ret)
+ goto err_unregister_dma;
+
+ return 0;
+
+err_unregister_dma:
+ dma_async_device_unregister(&bdev->common);
+err_disable_clk:
+ clk_disable_unprepare(bdev->bamclk);
+ return ret;
+}
+
+static int bam_dma_remove(struct platform_device *pdev)
+{
+ struct bam_device *bdev = platform_get_drvdata(pdev);
+
+ dma_async_device_unregister(&bdev->common);
+
+ of_dma_controller_free(pdev->dev.of_node);
+
+ clk_disable_unprepare(bdev->bamclk);
+
+ return 0;
+}
+
+static const struct of_device_id bam_of_match[] = {
+ { .compatible = "qcom,bam-v1.4.0", },
+ { .compatible = "qcom,bam-v1.4.1", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, bam_of_match);
+
+static struct platform_driver bam_dma_driver = {
+ .probe = bam_dma_probe,
+ .remove = bam_dma_remove,
+ .driver = {
+ .name = "bam-dma-engine",
+ .owner = THIS_MODULE,
+ .of_match_table = bam_of_match,
+ },
+};
+
+module_platform_driver(bam_dma_driver);
+
+MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
+MODULE_DESCRIPTION("QCOM BAM DMA engine driver");
+MODULE_LICENSE("GPL v2");
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply related
* [Patch v3 0/2] Add Qualcomm BAM dmaengine driver
From: Andy Gross @ 2014-01-28 6:27 UTC (permalink / raw)
To: linux-arm-kernel
This patch set introduces the dmaengine driver for the Qualcomm Bus Access
Manager (BAM) DMA controller present on MSM 8x74 devices. A number of the
on-chip devices have their own BAM DMA controller and use it to move data
between system memory and peripherals or between two peripherals.
The initial version of this driver will only support slave DMA operations
between system memory and peripherals.
Changes from v2:
- Corrected Kconfig dependencies
- Moved execution environment ID to controller DT binding. The EE is
a global setting across all of the channels on the controller.
- Combined header into source file.
- Corrected copyright date.
- Moved channel hardware initialization to occur when channel is used
for the first time.
- Converted dma_alloc_coherent to dma_alloc_writecombine
- Removed unecessary reset of channel from the dma terminate_all
- Corrected usage of EE in irq handler and channel configuration
functions.
- Changed resource functions inside probe to use correct APIs.
- Removed dma filter function and modified dma_xlate to use
dma_get_slave_channel API
- Fixed various nit comments
Changes from v1:
- Converted driver to use virt-dma
- Reworked probe function per review comments
- tx_status function now computes and returns residuals
- Removed proprietary slave config. Removed associated include file.
- Renamed files to reflect vendor name instead of specific device
- Converted to use (readl|writel)_relaxed w/ appropriate barriers
- Removed unions in favor of standard types.
Andy Gross (2):
dmaengine: add Qualcomm BAM dma driver
dmaengine: qcom_bam_dma: Add device tree binding
.../devicetree/bindings/dma/qcom_bam_dma.txt | 52 +
drivers/dma/Kconfig | 9 +
drivers/dma/Makefile | 1 +
drivers/dma/qcom_bam_dma.c | 1083 ++++++++++++++++++++
4 files changed, 1145 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/qcom_bam_dma.txt
create mode 100644 drivers/dma/qcom_bam_dma.c
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* [PATCH] clk: remove unnecessary substitution
From: Masahiro Yamada @ 2014-01-28 6:09 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
---
drivers/clk/clk.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 2b38dc9..d97b313 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1637,7 +1637,7 @@ static struct clk *__clk_init_parent(struct clk *clk)
if (clk->num_parents == 1) {
if (IS_ERR_OR_NULL(clk->parent))
- ret = clk->parent = __clk_lookup(clk->parent_names[0]);
+ clk->parent = __clk_lookup(clk->parent_names[0]);
ret = clk->parent;
goto out;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH] arm64: add DSB after icache flush in __flush_icache_all()
From: Vinayak Kale @ 2014-01-28 5:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140127122536.GE32608@arm.com>
On Mon, Jan 27, 2014 at 5:55 PM, Catalin Marinas
<catalin.marinas@arm.com> wrote:
> On Mon, Jan 27, 2014 at 11:59:44AM +0000, Vinayak Kale wrote:
>> Add DSB after icache flush operation.
>>
>> Signed-off-by: Vinayak Kale <vkale@apm.com>
>
> I think we should also mention that this function is used for user
> addresses and an ISB is not required because of an exception return
> before executing user instructions.
Okay, will mention this. Thanks.
>
> --
> Catalin
^ permalink raw reply
* [PATCH] arm64: add DSB after icache flush in __flush_icache_all()
From: Vinayak Kale @ 2014-01-28 5:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140127121613.GB6547@mudshark.cambridge.arm.com>
On Mon, Jan 27, 2014 at 5:46 PM, Will Deacon <will.deacon@arm.com> wrote:
> Hi Vinayak,
>
> On Mon, Jan 27, 2014 at 11:59:44AM +0000, Vinayak Kale wrote:
>> Add DSB after icache flush operation.
>
> Please elaborate a bit on what this achieves (i.e. completion of the
> maintenance operation).
Okay.
>
>> Signed-off-by: Vinayak Kale <vkale@apm.com>
>> ---
>> arch/arm64/include/asm/cacheflush.h | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
>> index fea9ee3..88932498 100644
>> --- a/arch/arm64/include/asm/cacheflush.h
>> +++ b/arch/arm64/include/asm/cacheflush.h
>> @@ -116,6 +116,7 @@ extern void flush_dcache_page(struct page *);
>> static inline void __flush_icache_all(void)
>> {
>> asm("ic ialluis");
>
> This needs a "memory" clobber to prevent re-ordering by GCC. We should
> probably check the rest of the code for other occurrences of this too.
Okay.
>
>> + dsb();
>
> Can you make a corresponding change for arch/arm/ too, please? I think we're
> missing the barrier there as well.
I could have, but I don't have hardware to test it on.
>
> Will
^ permalink raw reply
* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
From: Thomas Abraham @ 2014-01-28 5:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140127202543.4167.83362@quantum>
Hi Mike,
On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> wrote:
> Quoting Thomas Abraham (2014-01-18 04:10:51)
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> On some platforms such as the Samsung Exynos, changing the frequency
>> of the CPU clock requires changing the frequency of the PLL that is
>> supplying the CPU clock. To change the frequency of the PLL, the CPU
>> clock is temporarily reparented to another parent clock.
>>
>> The clock frequency of this temporary parent clock could be much higher
>> than the clock frequency of the PLL at the time of reparenting. Due
>> to the temporary increase in the CPU clock speed, the CPU (and any other
>> components in the CPU clock domain such as dividers, mux, etc.) have to
>> to be operated at a higher voltage level, called the safe voltage level.
>> This patch adds optional support to temporarily switch to a safe voltage
>> level during CPU frequency transitions.
>>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>
> I'm not a fan of this change. This corner case should be abstracted away
> somehow. I had talked to Chander Kayshap previously about handling
> voltage changes in clock notifier callbacks, which then renders any
> voltage change as a trivial part of the clock rate transition. That
> means that this "safe voltage" thing could be handled automagically
> without any additional code in the CPUfreq driver.
>
> There are two nice ways to do this with the clock framework. First is
> explicit re-parenting with voltage scaling done in the clock rate-change
> notifiers:
>
> clk_set_parent(cpu_clk, temp_parent);
> /* implicit voltage scaling to "safe voltage" happens above */
> clk_set_rate(pll, some_rate);
> clk_set_parent(cpu_clk, pll);
> /* implicit voltage scaling to nominal OPP voltage happens above */
>
> The above sequence would require a separate exnyos CPUfreq driver, due
> to the added clk_set_parent logic.
>
> The second way to do this is to abstract the clk re-muxing logic out
> into the clk driver, which would allow cpufreq-cpu0 to be used for the
> exynos chips.
This is the approach this patch series takes (patch 2/7). The clock
re-muxing logic is handled by a clock driver code. The difference from
what you suggested is that the safe voltage (that may be optionally)
required before doing the re-muxing is handled here in cpufreq-cpu0
driver.
The safe voltage setup can be done in the notifier as you suggested.
But, doing that in cpufreq-cpu0 driver will help other platforms reuse
this feature if required. Also, if done here, the regulator handling
is localized in this driver which otherwise would need to be handled
in two places, cpufreq-cpu0 driver and the clock notifier.
So I tend to prefer the approach in this patch but I am willing to
consider any suggestions. Shawn, it would be helpful if you could let
us know your thoughts on this. I am almost done with testing the v3 of
this series and want to post it so if there are any objections to the
changes in this patch, please let me know.
Thanks,
Thomas.
>
> I'm more a fan of explicitly listing the Exact Steps for the cpu opp
> transition in a separate exynos-specific CPUfreq driver, but that's
> probably an unpopular view.
>
> Regards,
> Mike
>
>> ---
>> .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt | 7 ++++
>> drivers/cpufreq/cpufreq-cpu0.c | 37 +++++++++++++++++--
>> 2 files changed, 40 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> index f055515..37453ab 100644
>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> @@ -19,6 +19,12 @@ Optional properties:
>> - cooling-min-level:
>> - cooling-max-level:
>> Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
>> +- safe-opp: Certain platforms require that during a opp transition,
>> + a system should not go below a particular opp level. For such systems,
>> + this property specifies the minimum opp to be maintained during the
>> + opp transitions. The safe-opp value is a tuple with first element
>> + representing the safe frequency and the second element representing the
>> + safe voltage.
>>
>> Examples:
>>
>> @@ -36,6 +42,7 @@ cpus {
>> 396000 950000
>> 198000 850000
>> >;
>> + safe-opp = <396000 950000>
>> clock-latency = <61036>; /* two CLK32 periods */
>> #cooling-cells = <2>;
>> cooling-min-level = <0>;
>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
>> index 0c12ffc..075d3d1 100644
>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> @@ -27,6 +27,8 @@
>>
>> static unsigned int transition_latency;
>> static unsigned int voltage_tolerance; /* in percentage */
>> +static unsigned long safe_frequency;
>> +static unsigned long safe_voltage;
>>
>> static struct device *cpu_dev;
>> static struct clk *cpu_clk;
>> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>> volt_old = regulator_get_voltage(cpu_reg);
>> }
>>
>> - pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
>> + pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>> old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>> new_freq / 1000, volt ? volt / 1000 : -1);
>>
>> /* scaling up? scale voltage before frequency */
>> - if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
>> + if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
>> + new_freq >= safe_frequency) {
>> ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>> if (ret) {
>> pr_err("failed to scale voltage up: %d\n", ret);
>> return ret;
>> }
>> + } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
>> + /*
>> + * the scaled up voltage level for the new_freq is lower
>> + * than the safe voltage level. so set safe_voltage
>> + * as the intermediate voltage level and revert it
>> + * back after the frequency has been changed.
>> + */
>> + ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
>> + if (ret) {
>> + pr_err("failed to set safe voltage: %d\n", ret);
>> + return ret;
>> + }
>> }
>>
>> ret = clk_set_rate(cpu_clk, freq_exact);
>> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>> }
>>
>> /* scaling down? scale voltage after frequency */
>> - if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
>> + if (!IS_ERR(cpu_reg) &&
>> + (new_freq < old_freq || new_freq < safe_frequency)) {
>> ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>> if (ret) {
>> pr_err("failed to scale voltage down: %d\n", ret);
>> @@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
>>
>> static int cpu0_cpufreq_probe(struct platform_device *pdev)
>> {
>> + const struct property *prop;
>> + struct dev_pm_opp *opp;
>> struct device_node *np;
>> int ret;
>>
>> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>> goto out_put_node;
>> }
>>
>> + prop = of_find_property(np, "safe-opp", NULL);
>> + if (prop) {
>> + if (prop->value && (prop->length / sizeof(u32)) == 2) {
>> + const __be32 *val;
>> + val = prop->value;
>> + safe_frequency = be32_to_cpup(val++);
>> + safe_voltage = be32_to_cpup(val);
>> + } else {
>> + pr_err("invalid safe-opp level specified\n");
>> + }
>> + }
>> +
>> of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
>>
>> if (of_property_read_u32(np, "clock-latency", &transition_latency))
>> transition_latency = CPUFREQ_ETERNAL;
>>
>> if (!IS_ERR(cpu_reg)) {
>> - struct dev_pm_opp *opp;
>> unsigned long min_uV, max_uV;
>> int i;
>>
>> --
>> 1.6.6.rc2
>>
^ permalink raw reply
* [RFC] drivers: irq-chip: Enable SGI's for Secure-to-NonSecure communication use-cases
From: Hiremath, Vaibhav @ 2014-01-28 5:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87wqhl15wi.fsf@nbsps.com>
> -----Original Message-----
> From: Bill Pringlemeir [mailto:bpringlemeir at nbsps.com]
> Sent: Tuesday, January 28, 2014 2:47 AM
> To: Hiremath, Vaibhav
> Cc: linux-arm-kernel at lists.infradead.org
> Subject: Re: [RFC] drivers: irq-chip: Enable SGI's for Secure-to-NonSecure
> communication use-cases
>
>
> > From: Russell King - ARM Linux [mailto:linux at arm.linux.org.uk]
>
> >> So it seems that your intention is to use the existing infrastructure
> >> for this by directing SGIs through the normal IRQ processing.
> >> To that idea, I say no way.
>
> On 6 Jan 2014, hvaibhav at ti.com wrote:
>
> > You have any other alternative?
>
> I think you need to put Bhupesh Sharma's comment with this. The typical sane
> mode for GIC with TZ is to have the monitor mode toggle the IRQ/FIQ routing
> bits in the SCR (cp15) bits 1,2. That is, the IRQ goes direct to core and FIQ goes
> to monitor from the 'Normal' world. In the 'Secure' world, the FIQ goes direct
> to core and IRQ traps to monitor.
> The monitor mode vector table has a gateway from secure to normal for IRQ
> and gateway from normal to secure for FIQ.
>
> Now, consider the 'SMC' instruction and what is present in stuff like this,
>
> http://lwn.net/Articles/513756/
> mach-omap2/{omap-smc.S,omap-secure.c,omap-secure.h}
>
> Instead of messing around with the GIC, why not use something even more
> generic like the 'SMC' instruction. It has the same sort of 'end game'
> which is a trap to monitor mode. The monitor has to be a little smarter to
> determine which world called but this should always be the case; really you want
> to check this.
>
> Btw, the situation is the same no matter which world Linux is in. I don't think
> Linux can be the recipient of an 'SMC' call. But I think most use cases would put
> it in the 'normal world' and the SMC is fine.
>
May be I am missing something here,
I find your above two statements contradictory,
If we want to use SMC as you mentioned, and assuming Secure Monitor mode is intelligent
enough to determine the calling world (whether secure or non-secure),
then without Linux being recipient (in any world) of an 'SMC' call how can realtime switch possible
from secure world to non-secure world??
Just to clarify,
The need here is, to switch from secure world to non-secure world on any realtime (multiple) hardware events,
which in turn gets processed/handled in non-secure world.
In certain cases even we do not want non-secure world know about the hardware event. In this case, the
Processing of hardware event completely happens in secure world, and different event/trigger/info/message
goes to non-secure world. So just manipulating IRQ/FIQ routing will not solve the need here. :)
Thanks,
Vaibhav
^ permalink raw reply
* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
From: Thomas Abraham @ 2014-01-28 4:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140127071656.GB3135@S2101-09.ap.freescale.net>
Hi Shawn,
On Mon, Jan 27, 2014 at 12:46 PM, Shawn Guo <shawn.guo@linaro.org> wrote:
> On Sat, Jan 18, 2014 at 05:40:51PM +0530, Thomas Abraham wrote:
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> On some platforms such as the Samsung Exynos, changing the frequency
>> of the CPU clock requires changing the frequency of the PLL that is
>> supplying the CPU clock. To change the frequency of the PLL, the CPU
>> clock is temporarily reparented to another parent clock.
>>
>> The clock frequency of this temporary parent clock could be much higher
>> than the clock frequency of the PLL at the time of reparenting. Due
>> to the temporary increase in the CPU clock speed, the CPU (and any other
>> components in the CPU clock domain such as dividers, mux, etc.) have to
>> to be operated at a higher voltage level, called the safe voltage level.
>> This patch adds optional support to temporarily switch to a safe voltage
>> level during CPU frequency transitions.
>>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>> .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt | 7 ++++
>
> The devicetree list should be copied for this change.
Okay, will do in the next version.
>
>> drivers/cpufreq/cpufreq-cpu0.c | 37 +++++++++++++++++--
>> 2 files changed, 40 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> index f055515..37453ab 100644
>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> @@ -19,6 +19,12 @@ Optional properties:
>> - cooling-min-level:
>> - cooling-max-level:
>> Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
>> +- safe-opp: Certain platforms require that during a opp transition,
>> + a system should not go below a particular opp level. For such systems,
>> + this property specifies the minimum opp to be maintained during the
>> + opp transitions. The safe-opp value is a tuple with first element
>> + representing the safe frequency and the second element representing the
>> + safe voltage.
>>
>> Examples:
>>
>> @@ -36,6 +42,7 @@ cpus {
>> 396000 950000
>> 198000 850000
>> >;
>> + safe-opp = <396000 950000>
>> clock-latency = <61036>; /* two CLK32 periods */
>> #cooling-cells = <2>;
>> cooling-min-level = <0>;
>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
>> index 0c12ffc..075d3d1 100644
>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> @@ -27,6 +27,8 @@
>>
>> static unsigned int transition_latency;
>> static unsigned int voltage_tolerance; /* in percentage */
>> +static unsigned long safe_frequency;
>> +static unsigned long safe_voltage;
>>
>> static struct device *cpu_dev;
>> static struct clk *cpu_clk;
>> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>> volt_old = regulator_get_voltage(cpu_reg);
>> }
>>
>> - pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
>> + pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>
> This is an unnecessary change?
Yes, sorry missed that.
>
> Otherwise,
>
> Acked-by: Shawn Guo <shawn.guo@linaro.org>
Thanks for your review.
Regards,
Thomas.
>
> Shawn
>
>> old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>> new_freq / 1000, volt ? volt / 1000 : -1);
>>
>> /* scaling up? scale voltage before frequency */
>> - if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
>> + if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
>> + new_freq >= safe_frequency) {
>> ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>> if (ret) {
>> pr_err("failed to scale voltage up: %d\n", ret);
>> return ret;
>> }
>> + } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
>> + /*
>> + * the scaled up voltage level for the new_freq is lower
>> + * than the safe voltage level. so set safe_voltage
>> + * as the intermediate voltage level and revert it
>> + * back after the frequency has been changed.
>> + */
>> + ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
>> + if (ret) {
>> + pr_err("failed to set safe voltage: %d\n", ret);
>> + return ret;
>> + }
>> }
>>
>> ret = clk_set_rate(cpu_clk, freq_exact);
>> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>> }
>>
>> /* scaling down? scale voltage after frequency */
>> - if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
>> + if (!IS_ERR(cpu_reg) &&
>> + (new_freq < old_freq || new_freq < safe_frequency)) {
>> ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>> if (ret) {
>> pr_err("failed to scale voltage down: %d\n", ret);
>> @@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
>>
>> static int cpu0_cpufreq_probe(struct platform_device *pdev)
>> {
>> + const struct property *prop;
>> + struct dev_pm_opp *opp;
>> struct device_node *np;
>> int ret;
>>
>> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>> goto out_put_node;
>> }
>>
>> + prop = of_find_property(np, "safe-opp", NULL);
>> + if (prop) {
>> + if (prop->value && (prop->length / sizeof(u32)) == 2) {
>> + const __be32 *val;
>> + val = prop->value;
>> + safe_frequency = be32_to_cpup(val++);
>> + safe_voltage = be32_to_cpup(val);
>> + } else {
>> + pr_err("invalid safe-opp level specified\n");
>> + }
>> + }
>> +
>> of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
>>
>> if (of_property_read_u32(np, "clock-latency", &transition_latency))
>> transition_latency = CPUFREQ_ETERNAL;
>>
>> if (!IS_ERR(cpu_reg)) {
>> - struct dev_pm_opp *opp;
>> unsigned long min_uV, max_uV;
>> int i;
>>
>> --
>> 1.6.6.rc2
>>
>
^ permalink raw reply
* [RFC PATCH 0/3] In-kernel PSCI v0.2 emulation for KVM ARM/ARM64
From: Anup Patel @ 2014-01-28 4:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390309301-28424-1-git-send-email-anup.patel@linaro.org>
On Tue, Jan 21, 2014 at 6:31 PM, Anup Patel <anup.patel@linaro.org> wrote:
> Currently, KVM ARM/ARM64 only provides in-kernel emulation of Power State
> and Coordination Interface (PSCI) v0.1.
>
> This patchset aims at providing newer PSCI v0.2 for KVM ARM/ARM64 VCPUs
> such that it does not break current KVM ARM/ARM64 ABI. Also, the patchset
> provides emulation of only few PSCI v0.2 functions such as PSCI_VERSION,
> CPU_ON, and CPU_OFF. Emulation of other PSCI v0.2 functions will be added
> later.
>
> The user space tools (i.e. QEMU or KVMTOOL) will have to explicitly enable
> KVM_ARM_VCPU_PSCI_0_2 feature using KVM_ARM_VCPU_INIT ioctl for providing
> PSCI v0.2 to VCPUs.
>
> Anup Patel (3):
> KVM: Add capability to advertise PSCI v0.2 support
> ARM/ARM64: KVM: Add support for PSCI v0.2 emulation
> KVM: Documentation: Add info regarding KVM_ARM_VCPU_PSCI_0_2 feature
>
> Documentation/virtual/kvm/api.txt | 2 +
> arch/arm/include/asm/kvm_host.h | 2 +-
> arch/arm/include/uapi/asm/kvm.h | 39 ++++++++++++++++--
> arch/arm/kvm/arm.c | 6 ++-
> arch/arm/kvm/psci.c | 79 ++++++++++++++++++++++++++++++-------
> arch/arm64/include/asm/kvm_host.h | 2 +-
> arch/arm64/include/uapi/asm/kvm.h | 39 ++++++++++++++++--
> include/uapi/linux/kvm.h | 1 +
> 8 files changed, 146 insertions(+), 24 deletions(-)
>
> --
> 1.7.9.5
>
> _______________________________________________
> kvmarm mailing list
> kvmarm at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm
Hi All,
Please provide feedback and comments on this patchset.
Regards,
Anup
^ permalink raw reply
* [PATCH] ARM: dts: imx28-m28cu3: Remove 'reset-active-high'
From: Marek Vasut @ 2014-01-28 3:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390596324-20904-1-git-send-email-festevam@gmail.com>
On Friday, January 24, 2014 at 09:45:24 PM, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@freescale.com>
>
> The 'reset-active-high' property is not defined anywhere, so just remove
> it.
>
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Acked-by: Marek Vasut <marex@denx.de>
Best regards,
Marek Vasut
^ permalink raw reply
* [PATCH v2] dma: Add Xilinx AXI Video Direct Memory Access Engine driver support
From: Vinod Koul @ 2014-01-28 3:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CA+mB=1JvnTcyRnuvdnW1BCeiMLSTMrrAbKwVKgwFUmWrVuXzSw@mail.gmail.com>
On Mon, Jan 27, 2014 at 06:42:36PM +0530, Srikanth Thokala wrote:
> Hi Lars/Vinod,
> >> The question here i think would be waht this device supports? Is the hardware
> >> capable of doing interleaved transfers, then would make sense.
> >
> > The hardware does 2D transfers. The parameters for a transfer are height,
> > width and stride. That's only a subset of what interleaved transfers can be
> > (xt->num_frames must be one for 2d transfers). But if I remember correctly
> > there has been some discussion on this in the past and the result of that
> > discussion was that using interleaved transfers for 2D transfers is
> > preferred over adding a custom API for 2D transfers.
>
> I went through the prep_interleaved_dma API and I see only one descriptor
> is prepared per API call (i.e. per frame). As our IP supports upto 16 frame
> buffers (can be more in future), isn't it less efficient compared to the
> prep_slave_sg where we get a single sg list and can prepare all the descriptors
> (of non-contiguous buffers) in one go? Correct me, if am wrong and let me
> know your opinions.
Well the descriptor maybe one, but that can represent multiple frames, for
example 16 as in your case. Can you read up the documentation of how multiple
frames are passed. Pls see include/linux/dmaengine.h
/**
* Interleaved Transfer Request
* ----------------------------
* A chunk is collection of contiguous bytes to be transfered.
* The gap(in bytes) between two chunks is called inter-chunk-gap(ICG).
* ICGs may or maynot change between chunks.
* A FRAME is the smallest series of contiguous {chunk,icg} pairs,
* that when repeated an integral number of times, specifies the transfer.
* A transfer template is specification of a Frame, the number of times
* it is to be repeated and other per-transfer attributes.
*
* Practically, a client driver would have ready a template for each
* type of transfer it is going to need during its lifetime and
* set only 'src_start' and 'dst_start' before submitting the requests.
*
*
* | Frame-1 | Frame-2 | ~ | Frame-'numf' |
* |====....==.===...=...|====....==.===...=...| ~ |====....==.===...=...|
*
* == Chunk size
* ... ICG
*/
--
~Vinod
^ permalink raw reply
* [PATCH RFC 00/73] tree-wide: clean up some no longer required #include <linux/init.h>
From: Benjamin Herrenschmidt @ 2014-01-28 3:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140123003838.GA10182@windriver.com>
On Wed, 2014-01-22 at 19:38 -0500, Paul Gortmaker wrote:
> Thanks, it was a great help as it uncovered a few issues in fringe arch
> that I didn't have toolchains for, and I've fixed all of those up.
>
> I've noticed that powerpc has been un-buildable for a while now; I have
> used this hack patch locally so I could run the ppc defconfigs to check
> that I didn't break anything. Maybe useful for linux-next in the
> interim? It is a hack patch -- Not-Signed-off-by: Paul Gortmaker. :)
Can you and/or Aneesh submit that as a proper patch (with S-O-B
etc...) ?
Thanks !
Cheers,
Ben.
> Paul.
> --
>
> diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
> index d27960c89a71..d0f070a2b395 100644
> --- a/arch/powerpc/include/asm/pgtable-ppc64.h
> +++ b/arch/powerpc/include/asm/pgtable-ppc64.h
> @@ -560,9 +560,9 @@ extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
> pmd_t *pmdp);
>
> #define pmd_move_must_withdraw pmd_move_must_withdraw
> -typedef struct spinlock spinlock_t;
> -static inline int pmd_move_must_withdraw(spinlock_t *new_pmd_ptl,
> - spinlock_t *old_pmd_ptl)
> +struct spinlock;
> +static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
> + struct spinlock *old_pmd_ptl)
> {
> /*
> * Archs like ppc64 use pgtable to store per pmd
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* [PATCH v2] dma: Add Xilinx AXI Video Direct Memory Access Engine driver support
From: Vinod Koul @ 2014-01-28 3:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52E54849.2000208@metafoo.de>
On Sun, Jan 26, 2014 at 06:39:21PM +0100, Lars-Peter Clausen wrote:
> On 01/26/2014 02:59 PM, Vinod Koul wrote:
> > On Fri, Jan 24, 2014 at 02:24:27PM +0100, Lars-Peter Clausen wrote:
> >> On 01/24/2014 12:16 PM, Srikanth Thokala wrote:
> >>> Hi Lars,
> >>>
> >>> On Thu, Jan 23, 2014 at 4:55 PM, Lars-Peter Clausen <lars@metafoo.de> wrote:
> >>>> On 01/22/2014 05:52 PM, Srikanth Thokala wrote:
> >>>> [...]
> >>>>> +/**
> >>>>> + * xilinx_vdma_device_control - Configure DMA channel of the device
> >>>>> + * @dchan: DMA Channel pointer
> >>>>> + * @cmd: DMA control command
> >>>>> + * @arg: Channel configuration
> >>>>> + *
> >>>>> + * Return: '0' on success and failure value on error
> >>>>> + */
> >>>>> +static int xilinx_vdma_device_control(struct dma_chan *dchan,
> >>>>> + enum dma_ctrl_cmd cmd, unsigned long arg)
> >>>>> +{
> >>>>> + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
> >>>>> +
> >>>>> + switch (cmd) {
> >>>>> + case DMA_TERMINATE_ALL:
> >>>>> + xilinx_vdma_terminate_all(chan);
> >>>>> + return 0;
> >>>>> + case DMA_SLAVE_CONFIG:
> >>>>> + return xilinx_vdma_slave_config(chan,
> >>>>> + (struct xilinx_vdma_config *)arg);
> >>>>
> >>>> You really shouldn't be overloading the generic API with your own semantics.
> >>>> DMA_SLAVE_CONFIG should take a dma_slave_config and nothing else.
> >>>
> >>> Ok. The driver needs few additional configuration from the slave
> >>> device like Vertical
> >>> Size, Horizontal Size, Stride etc., for the DMA transfers, in that case do you
> >>> suggest me to define a separate dma_ctrl_cmd like the one FSLDMA_EXTERNAL_START
> >>> defined for Freescale drivers?
> >>
> >> In my opinion it is not a good idea to have driver implement a generic API,
> >> but at the same time let the driver have custom semantics for those API
> >> calls. It's a bit like having a gpio driver that expects 23 and 42 as the
> >> values passed to gpio_set_value instead of 0 and 1. It completely defeats
> >> the purpose of a generic API, namely that you are able to write generic code
> >> that makes use of the API without having to know about which implementation
> >> API it is talking to. The dmaengine framework provides the
> >> dmaengine_prep_interleaved_dma() function to setup two dimensional
> >> transfers, e.g. take a look at sirf-dma.c or imx-dma.c.
> >
> > The question here i think would be waht this device supports? Is the hardware
> > capable of doing interleaved transfers, then would make sense.
>
> The hardware does 2D transfers. The parameters for a transfer are height,
> width and stride. That's only a subset of what interleaved transfers can be
> (xt->num_frames must be one for 2d transfers). But if I remember correctly
> there has been some discussion on this in the past and the result of that
> discussion was that using interleaved transfers for 2D transfers is
> preferred over adding a custom API for 2D transfers.
Yup that would be my recomendation. Moving this driver to interleaved API seems
right to me
--
~Vinod
^ permalink raw reply
* [RFC PATCH V2 1/4] pci: APM X-Gene PCIe controller driver
From: Tanmay Inamdar @ 2014-01-28 2:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAErSpo5zMd_k407tvzPS85Nub9p2KMQnHJLTqd3eyvjdgfVtLg@mail.gmail.com>
On Mon, Jan 27, 2014 at 4:55 PM, Bjorn Helgaas <bhelgaas@google.com> wrote:
> We're only seeing Arnd's side of the conversation on linux-pci.
> Tanmay, are your messages being rejected because they're too "fancy",
> per the definition here: http://vger.kernel.org/majordomo-info.html ?
>
Thanks for pointing out. I am not sure though what's being detected as
fancy. I checked that my emails are received as plaintext on
majordomo. They are also displayed fine on LKML.
In this email, I have tried to keep the format of to: and cc: same as
first email in the thread. Not sure if this fixes the problem.
Again.. sorry for spamming.
> On Sat, Jan 25, 2014 at 1:11 PM, Arnd Bergmann <arnd@arndb.de> wrote:
>> On Friday 24 January 2014 13:28:22 Tanmay Inamdar wrote:
>>> On Thu, Jan 16, 2014 at 5:10 PM, Tanmay Inamdar <tinamdar@apm.com> wrote:
>>> > On Wed, Jan 15, 2014 at 4:39 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>>> >> On Wednesday 15 January 2014, Tanmay Inamdar wrote:
>>
>>> >>
>>> >>> +static void xgene_pcie_poll_linkup(struct xgene_pcie_port *port, u32 *lanes)
>>> >>> +{
>>> >>> + void *csr_base = port->csr_base;
>>> >>> + u32 val32;
>>> >>> + u64 start_time, time;
>>> >>> +
>>> >>> + /*
>>> >>> + * A component enters the LTSSM Detect state within
>>> >>> + * 20ms of the end of fundamental core reset.
>>> >>> + */
>>> >>> + msleep(XGENE_LTSSM_DETECT_WAIT);
>>> >>> + port->link_up = 0;
>>> >>> + start_time = jiffies;
>>> >>> + do {
>>> >>> + val32 = readl(csr_base + PCIECORE_CTLANDSTATUS);
>>> >>> + if (val32 & LINK_UP_MASK) {
>>> >>> + port->link_up = 1;
>>> >>> + port->link_speed = PIPE_PHY_RATE_RD(val32);
>>> >>> + val32 = readl(csr_base + BRIDGE_STATUS_0);
>>> >>> + *lanes = val32 >> 26;
>>> >>> + }
>>> >>> + time = jiffies_to_msecs(jiffies - start_time);
>>> >>> + } while ((!port->link_up) || (time <= XGENE_LTSSM_L0_WAIT));
>>> >>> +}
>>> >>
>>> >> Maybe another msleep() in the loop? It seems weird to first do an
>>> >> unconditional sleep but then busy-wait for the result.
>>> >
>>> > ok.
>>>
>>> This loop can execute for maximum 4 msec. So putting msleep(1) won't
>>> get us much.
>>
>> 4 msec is still quite a long time for a busy loop that can be spent doing
>> useful work in another thread.
>>
>>> >>
>>> >> Another general note: Your "compatible" strings are rather unspecific.
>>> >> Do you have a version number for this IP block? I suppose that it's related
>>> >> to one that has been used in other chips before, or will be used in future
>>> >> chips, if it's not actually licensed from some other company.
>>> >
>>> > I will have to check this.
>>> >
>>>
>>> We have decided to stick with current compatible string for now.
>>
>> Can you elaborate on your reasoning? Does this mean X-Gene is a one-off
>> product and you won't be doing any new chips based on the same hardware
>> components?
>>
>> Arnd
^ permalink raw reply
* [PATCH] arm64: Add pdev_archdata for dmamask
From: Laura Abbott @ 2014-01-28 1:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140127193149.GV15937@n2100.arm.linux.org.uk>
On 1/27/2014 11:31 AM, Russell King - ARM Linux wrote:
> On Mon, Jan 27, 2014 at 09:52:57AM -0800, Laura Abbott wrote:
>> The dma_mask for a device structure is a pointer. This pointer
>> needs to be set up before the dma mask can actually be set. Most
>> frameworks in the kernel take care of setting this up properly but
>> platform devices that don't follow a regular bus structure may not
>> ever have this set. As a result, checks such as dma_capable will
>> always return false on a raw platform device and dma_set_mask will
>> always return -EIO. Fix this by adding a dma_mask in the
>> platform_device archdata and setting it to be the dma_mask. Devices
>> used in other frameworks can change this as needed.
>
> You shouldn't need to do this. I went through a lot of the drivers we
> currently have, fixing them up in various manners. The basic rules
> for this stuff are:
>
> - It is the responsibility of the code creating the device to set a
> reasonable default for the dma mask according to the bus and whether
> DMA is supportable.
>
> - It is the responsibility of the driver _always_ to make a call to
> dma_set_mask() and/or dma_set_coherent_mask() according to the
> driver's needs if the driver is going to be using DMA.
>
> As a work-around for the buggy situation we have in the kernel with DT,
> various buggy workarounds have been incorporated into drivers which
> involve writing directly to the DMA masks, and other such games. None
> of that is necessary when the dma_coerce_*() functions are used - but
> these are a stop-gap until the DT code gets fixed.
>
> The real answer here is to make DT conform to the first point above
> and not add yet another different hack to the kernel.
>
powerpc ran into this exact problem before and fixed it using this
method (a77ce8167cc1d0370fcb1d79b367d62e050cb2b0
"driver core: Add ability for arch code to setup pdev_archdata" and
314b02f503c2c219fde0fcf6f086fda415f8a847 "powerpc: implement
arch_setup_pdev_archdata") so there is at least some precedent for this
method.
Are there patches/discussion somewhere else on what a proper solution
would be in the DT?
Thanks,
Laura
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ 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