* [PATCH 00/15] improve function-level documentation
From: Julia Lawall @ 2016-10-01 19:46 UTC (permalink / raw)
To: linux-arm-kernel
These patches fix cases where the documentation above a function definition
is not consistent with the function header. Issues are detected using the
semantic patch below (http://coccinelle.lip6.fr/). Basically, the semantic
patch parses a file to find comments, then matches each function header,
and checks that the name and parameter list in the function header are
compatible with the comment that preceeds it most closely.
// <smpl>
@initialize:ocaml@
@@
let tbl = ref []
let fnstart = ref []
let success = Hashtbl.create 101
let thefile = ref ""
let parsed = ref []
let nea = ref []
let parse file =
thefile := List.nth (Str.split (Str.regexp "linux-next/") file) 1;
let i = open_in file in
let startline = ref 0 in
let fn = ref "" in
let ids = ref [] in
let rec inside n =
let l = input_line i in
let n = n + 1 in
match Str.split_delim (Str.regexp_string "*/") l with
before::after::_ ->
(if not (!fn = "")
then tbl := (!startline,n,!fn,List.rev !ids)::!tbl);
startline := 0;
fn := "";
ids := [];
outside n
| _ ->
(match Str.split (Str.regexp "[ \t]+") l with
"*"::name::rest ->
let len = String.length name in
(if !fn = "" && len > 2 && String.sub name (len-2) 2 = "()"
then fn := String.sub name 0 (len-2)
else if !fn = "" && (not (rest = [])) && List.hd rest = "-"
then
if String.get name (len-1) = ':'
then fn := String.sub name 0 (len-1)
else fn := name
else if not(!fn = "") && len > 2 &&
String.get name 0 = '@' && String.get name (len-1) = ':'
then ids := (String.sub name 1 (len-2)) :: !ids);
| _ -> ());
inside n
and outside n =
let l = input_line i in
let n = n + 1 in
if String.length l > 2 && String.sub l 0 3 = "/**"
then
begin
startline := n;
inside n
end
else outside n in
try outside 0 with End_of_file -> ()
let hashadd tbl k v =
let cell =
try Hashtbl.find tbl k
with Not_found ->
let cell = ref [] in
Hashtbl.add tbl k cell;
cell in
cell := v :: !cell
@script:ocaml@
@@
tbl := [];
fnstart := [];
Hashtbl.clear success;
parsed := [];
nea := [];
parse (List.hd (Coccilib.files()))
@r@
identifier f;
position p;
@@
f at p(...) { ... }
@script:ocaml@
p << r.p;
f << r.f;
@@
parsed := f :: !parsed;
fnstart := (List.hd p).line :: !fnstart
@param@
identifier f;
type T;
identifier i;
parameter list[n] ps;
parameter list[n1] ps1;
position p;
@@
f@p(ps,T i,ps1) { ... }
@script:ocaml@
@@
tbl := List.rev (List.sort compare !tbl)
@script:ocaml@
p << param.p;
f << param.f;
@@
let myline = (List.hd p).line in
let prevline =
List.fold_left
(fun prev x ->
if x < myline
then max x prev
else prev)
0 !fnstart in
let _ =
List.exists
(function (st,fn,nm,ids) ->
if prevline < st && myline > st && prevline < fn && myline > fn
then
begin
(if not (String.lowercase f = String.lowercase nm)
then
Printf.printf "%s:%d %s doesn't match preceding comment: %s\n"
!thefile myline f nm);
true
end
else false)
!tbl in
()
@script:ocaml@
p << param.p;
n << param.n;
n1 << param.n1;
i << param.i;
f << param.f;
@@
let myline = (List.hd p).line in
let prevline =
List.fold_left
(fun prev x ->
if x < myline
then max x prev
else prev)
0 !fnstart in
let _ =
List.exists
(function (st,fn,nm,ids) ->
if prevline < st && myline > st && prevline < fn && myline > fn
then
begin
(if List.mem i ids then hashadd success (st,fn,nm) i);
(if ids = [] (* arg list seems not obligatory *)
then ()
else if not (List.mem i ids)
then
Printf.printf "%s:%d %s doesn't appear in ids: %s\n"
!thefile myline i (String.concat " " ids)
else if List.length ids <= n || List.length ids <= n1
then
(if not (List.mem f !nea)
then
begin
nea := f :: !nea;
Printf.printf "%s:%d %s not enough args\n" !thefile myline f;
end)
else
let foundid = List.nth ids n in
let efoundid = List.nth (List.rev ids) n1 in
if not(foundid = i || efoundid = i)
then
Printf.printf "%s:%d %s wrong arg in position %d: %s\n"
!thefile myline i n foundid);
true
end
else false)
!tbl in
()
@script:ocaml@
@@
List.iter
(function (st,fn,nm,ids) ->
if List.mem nm !parsed
then
let entry =
try !(Hashtbl.find success (st,fn,nm))
with Not_found -> [] in
List.iter
(fun id ->
if not (List.mem id entry) && not (id = "...")
then Printf.printf "%s:%d %s not used\n" !thefile st id)
ids)
!tbl
// </smpl>
---
drivers/clk/keystone/pll.c | 4 ++--
drivers/clk/sunxi/clk-mod0.c | 2 +-
drivers/clk/tegra/cvb.c | 10 +++++-----
drivers/dma-buf/sw_sync.c | 6 +++---
drivers/gpu/drm/gma500/intel_i2c.c | 3 +--
drivers/gpu/drm/omapdrm/omap_drv.c | 4 ++--
drivers/irqchip/irq-metag-ext.c | 1 -
drivers/irqchip/irq-vic.c | 1 -
drivers/mfd/tc3589x.c | 4 ++--
drivers/power/supply/ab8500_fg.c | 8 ++++----
drivers/power/supply/abx500_chargalg.c | 1 +
drivers/power/supply/intel_mid_battery.c | 2 +-
drivers/power/supply/power_supply_core.c | 4 ++--
fs/crypto/crypto.c | 4 ++--
fs/crypto/fname.c | 4 ++--
fs/ubifs/file.c | 2 +-
fs/ubifs/gc.c | 2 +-
fs/ubifs/lprops.c | 2 +-
fs/ubifs/lpt_commit.c | 4 +---
fs/ubifs/replay.c | 2 +-
lib/kobject_uevent.c | 6 +++---
lib/lru_cache.c | 4 ++--
lib/nlattr.c | 2 +-
23 files changed, 39 insertions(+), 43 deletions(-)
^ permalink raw reply
* [PATCH] ARM: dts: rockchip: Reserve unusable memory region on rk3066
From: Heiko Stuebner @ 2016-10-01 19:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001181711.GB17554@remoulade>
Am Samstag, 1. Oktober 2016, 19:17:11 CEST schrieb Mark Rutland:
> Hi,
>
> On Sat, Oct 01, 2016 at 04:09:39PM +0200, =?UTF-8?q?Pawe=C5=82=20Jarosz?=
wrote:
> > For some reason accessing memory region above 0xfe000000 freezes
> > system on rk3066. There is similiar bug on later rockchip soc (rk3288)
> > solved same way.
> >
> > Signed-off-by: Pawe? Jarosz <paweljarosz3691@gmail.com>
> > ---
> >
> > arch/arm/boot/dts/rk3066a.dtsi | 13 +++++++++++++
> > 1 file changed, 13 insertions(+)
> >
> > diff --git a/arch/arm/boot/dts/rk3066a.dtsi
> > b/arch/arm/boot/dts/rk3066a.dtsi index 0d0dae3..44c8956 100644
> > --- a/arch/arm/boot/dts/rk3066a.dtsi
> > +++ b/arch/arm/boot/dts/rk3066a.dtsi
> > @@ -93,6 +93,19 @@
> >
> > };
> >
> > };
> >
> > + reserved-memory {
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + ranges;
> > + /*
> > + * The rk3066 cannot use the memory area above 0x9F000000
> > + * for some unknown reason.
> > + */
> > + unusable at 9F000000 {
> > + reg = <0x9F000000 0x1000000>;
> > + };
>
> I don't think this is a sane workaround, but it is at best difficult to
> tell, given there's no reason given for why this memory is unusable.
>
> For instance, if bus accesses to this address hang, then this patch only
> makes the hand less likely, since the kernel will still map the region (and
> therefore the CPU can perform speculative accesses).
>
> Are issues with this memory consistently seen in practice?
>
> Can you enable CONFIG_MEMTEST and pass 'memtest' to the kernel, to determine
> if the memory is returning erroneous values?
just for the sake of completeness, on the rk3288 the issue was the dma not
being able to access the specific memory region (interestingly also the last
16MB but of the 4GB area supported on the rk3288). So memory itself was ok,
just dma access to it failed.
We didn't find any other sane solution to limit the dma access in a general way
at the time, so opted for just blocking the memory region (as it was similarly
only
In the patch above, the newly blocked area is in the middle of the two 1gb
memory areas (0x60000000-0xa0000000-1, 0xa0000000-0xe0000000-1).
Pavel, apart from Mark's CONFIG_MEMTEST request above could you also specifiy
what type of error you see please?
Thanks
Heiko
^ permalink raw reply
* [PATCH] ARM: dts: rockchip: Reserve unusable memory region on rk3066
From: Mark Rutland @ 2016-10-01 18:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001140939.GA31220@vaio-ubuntu>
Hi,
On Sat, Oct 01, 2016 at 04:09:39PM +0200, =?UTF-8?q?Pawe=C5=82=20Jarosz?= wrote:
> For some reason accessing memory region above 0xfe000000 freezes
> system on rk3066. There is similiar bug on later rockchip soc (rk3288)
> solved same way.
>
> Signed-off-by: Pawe? Jarosz <paweljarosz3691@gmail.com>
> ---
> arch/arm/boot/dts/rk3066a.dtsi | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
> index 0d0dae3..44c8956 100644
> --- a/arch/arm/boot/dts/rk3066a.dtsi
> +++ b/arch/arm/boot/dts/rk3066a.dtsi
> @@ -93,6 +93,19 @@
> };
> };
>
> + reserved-memory {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges;
> + /*
> + * The rk3066 cannot use the memory area above 0x9F000000
> + * for some unknown reason.
> + */
> + unusable at 9F000000 {
> + reg = <0x9F000000 0x1000000>;
> + };
I don't think this is a sane workaround, but it is at best difficult to tell,
given there's no reason given for why this memory is unusable.
For instance, if bus accesses to this address hang, then this patch only makes
the hand less likely, since the kernel will still map the region (and therefore
the CPU can perform speculative accesses).
Are issues with this memory consistently seen in practice?
Can you enable CONFIG_MEMTEST and pass 'memtest' to the kernel, to determine if
the memory is returning erroneous values?
Thanks,
Mark.
^ permalink raw reply
* [RFC] arm64: Enforce observed order for spinlock and data
From: Mark Rutland @ 2016-10-01 18:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <66a031ac2405e352ab0d5f19d7ddb8e9@codeaurora.org>
Hi Brent,
Evidently my questions weren't sufficiently clear; even with your answers it's
not clear to me what precise issue you're attempting to solve. I've tried to be
more specific this time.
At a high-level, can you clarify whether you're attempting to solve is:
(a) a functional correctness issue (e.g. data corruption)
(b) a performance issue
And whether this was seen in practice, or found through code inspection?
On Sat, Oct 01, 2016 at 12:11:36PM -0400, bdegraaf at codeaurora.org wrote:
> On 2016-09-30 15:32, Mark Rutland wrote:
> >On Fri, Sep 30, 2016 at 01:40:57PM -0400, Brent DeGraaf wrote:
> >>+ * so LSE needs an explicit barrier here as well. Without this, the
> >>+ * changed contents of the area protected by the spinlock could be
> >>+ * observed prior to the lock.
> >>+ */
> >
> >By whom? We generally expect that if data is protected by a lock, you take
> >the lock before accessing it. If you expect concurrent lockless readers,
> >then there's a requirement on the writer side to explicitly provide the
> >ordering it requires -- spinlocks are not expected to provide that.
>
> More details are in my response to Robin, but there is an API arm64 supports
> in spinlock.h which is used by lockref to determine whether a lock is free or
> not. For that code to work properly without adding these barriers, that API
> needs to take the lock.
Can you please provide a concrete example of a case where things go wrong,
citing the code (or access pattern) in question? e.g. as in the commit messages
for:
8e86f0b409a44193 ("arm64: atomics: fix use of acquire + release for full barrier semantics)
859b7a0e89120505 ("mm/slub: fix lockups on PREEMPT && !SMP kernels")
(for the latter, I messed up the register -> var mapping in one paragraph, but
the style and reasoning is otherwise sound).
In the absence of a concrete example as above, it's very difficult to reason
about what the underlying issue is, and what a valid fix would be for said
issue.
> >What pattern of accesses are made by readers and writers such that there is
> >a problem?
Please note here I was asking specifically w.r.t. the lockref code, e.g. which
loads could see stale data, and what does the code do based on this value such
that there is a problem.
> I added the barriers to the readers/writers because I do not know these are
> not similarly abused. There is a lot of driver code out there, and ensuring
> order is the safest way to be sure we don't get burned by something similar
> to the lockref access.
Making the architecture-provided primitives overly strong harms performance and
efficiency (in general), makes the code harder to maintain and optimise in
future, and only masks the issue (which could crop up on other architectures,
for instance).
Thanks,
Mark.
^ permalink raw reply
* [PATCH 3/3] Revert "ACPI,PCI,IRQ: remove SCI penalize function"
From: Sinan Kaya @ 2016-10-01 17:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475343976-20744-1-git-send-email-okaya@codeaurora.org>
This reverts commit 9e5ed6d1fb87 ("ACPI,PCI,IRQ: remove SCI penalize
function"). SCI penalty API was replaced by the runtime penalty calculation
based on the value of acpi_gbl_FADT.sci_interrupt.
acpi_gbl_FADT.sci_interrupt type does not get updated at the right time
for some platforms and results in incorrect penalty assignment for PCI
IRQs as irq_get_trigger_type returns the wrong type.
Link: http://www.spinics.net/lists/linux-pci/msg54599.html
Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
---
arch/x86/kernel/acpi/boot.c | 1 +
drivers/acpi/pci_link.c | 34 ++++++++++++++--------------------
include/linux/acpi.h | 1 +
3 files changed, 16 insertions(+), 20 deletions(-)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 90d84c3..0ffd26e 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -453,6 +453,7 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger,
polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
+ acpi_penalize_sci_irq(bus_irq, trigger, polarity);
/*
* stash over-ride to indicate we've been here
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 06c2a11..6a2af19 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -495,27 +495,10 @@ static int acpi_irq_pci_sharing_penalty(int irq)
static int acpi_irq_get_penalty(int irq)
{
- int penalty = 0;
-
- /*
- * Penalize IRQ used by ACPI SCI. If ACPI SCI pin attributes conflict
- * with PCI IRQ attributes, mark ACPI SCI as ISA_ALWAYS so it won't be
- * use for PCI IRQs.
- */
- if (irq == acpi_gbl_FADT.sci_interrupt) {
- u32 type = irq_get_trigger_type(irq) & IRQ_TYPE_SENSE_MASK;
-
- if (type != IRQ_TYPE_LEVEL_LOW)
- penalty += PIRQ_PENALTY_ISA_ALWAYS;
- else
- penalty += PIRQ_PENALTY_PCI_USING;
- }
-
- if (irq < ACPI_MAX_ISA_IRQS)
- return penalty + acpi_irq_penalty[irq];
+ if (irq < ACPI_MAX_IRQS)
+ return acpi_irq_penalty[irq];
- penalty += acpi_irq_pci_sharing_penalty(irq);
- return penalty;
+ return acpi_irq_pci_sharing_penalty(irq);
}
int __init acpi_irq_penalty_init(void)
@@ -886,6 +869,17 @@ bool acpi_isa_irq_available(int irq)
acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
}
+void acpi_penalize_sci_irq(int irq, int trigger, int polarity)
+{
+ if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
+ if (trigger != ACPI_MADT_TRIGGER_LEVEL ||
+ polarity != ACPI_MADT_POLARITY_ACTIVE_LOW)
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_ALWAYS;
+ else
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
+ }
+}
+
/*
* Over-ride default table to reserve additional IRQs for use by ISA
* e.g. acpi_irq_isa=5
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 4d8452c..85ac7d5 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -318,6 +318,7 @@ struct pci_dev;
int acpi_pci_irq_enable (struct pci_dev *dev);
void acpi_penalize_isa_irq(int irq, int active);
bool acpi_isa_irq_available(int irq);
+void acpi_penalize_sci_irq(int irq, int trigger, int polarity);
void acpi_pci_irq_disable (struct pci_dev *dev);
extern int ec_read(u8 addr, u8 *val);
--
1.9.1
^ permalink raw reply related
* [PATCH 2/3] ACPI, PCI IRQ: add PCI_USING penalty for ISA interrupts
From: Sinan Kaya @ 2016-10-01 17:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475343976-20744-1-git-send-email-okaya@codeaurora.org>
The change introduced in commit 103544d86976 ("ACPI,PCI,IRQ: reduce
resource requirements") removed PCI_USING penalty from
acpi_pci_link_allocate function as there is no longer a fixed size penalty
array for both PCI and IRQ interrupts.
We need to add the PCI_USING penalty for ISA interrupts too if the link is
in use and matches our ISA IRQ number.
Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
---
drivers/acpi/pci_link.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index f3792f4..06c2a11 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -620,6 +620,10 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
acpi_device_bid(link->device));
return -ENODEV;
} else {
+ if (link->irq.active < ACPI_MAX_IRQS)
+ acpi_irq_penalty[link->irq.active] +=
+ PIRQ_PENALTY_PCI_USING;
+
printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
acpi_device_name(link->device),
acpi_device_bid(link->device), link->irq.active);
--
1.9.1
^ permalink raw reply related
* [PATCH 1/3] Revert "ACPI, PCI, IRQ: reduce static IRQ array size to 16"
From: Sinan Kaya @ 2016-10-01 17:46 UTC (permalink / raw)
To: linux-arm-kernel
This reverts commit 5c5087a55390 ("ACPI,PCI,IRQ: reduce static IRQ array
size to 16").
The code maintains a fixed size array for IRQ penalties. The array
gets updated by external calls such as acpi_penalize_sci_irq,
acpi_penalize_isa_irq to reflect the actual interrupt usage of the
system. Since the IRQ distribution is platform specific, this is
not known ahead of time. The IRQs get updated based on the SCI
interrupt number BIOS has chosen or the ISA IRQs that were assigned
to existing peripherals.
By the time ACPI gets initialized, this code tries to determine an
IRQ number based on penalty values in this array. It will try to locate
the IRQ with the least penalty assignment so that interrupt sharing is
avoided if possible.
A couple of notes about the external APIs:
1. These API can be called before the ACPI is started. Therefore, one
cannot assume that the PCI link objects are initialized for calculating
penalties.
2. The polarity and trigger information passed via the
acpi_penalize_sci_irq from the BIOS may not match what the IRQ subsystem
is reporting as the call might have been placed before the IRQ is
registered by the interrupt subsystem.
The previous change was in the direction to remove these external API and
try to calculate the penalties at runtime for the ISA path as well. This
didn't work out well with the existing platforms.
Restoring the old behavior for IRQ < 256 and the new behavior will remain
effective for IRQ >= 256.
Link: http://www.spinics.net/lists/linux-pci/msg54599.html
Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
---
drivers/acpi/pci_link.c | 35 ++++++++++++++++++-----------------
1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index c983bf7..f3792f4 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -438,6 +438,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
* enabled system.
*/
+#define ACPI_MAX_IRQS 256
#define ACPI_MAX_ISA_IRQS 16
#define PIRQ_PENALTY_PCI_POSSIBLE (16*16)
@@ -446,7 +447,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16)
#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16)
-static int acpi_isa_irq_penalty[ACPI_MAX_ISA_IRQS] = {
+static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */
@@ -511,7 +512,7 @@ static int acpi_irq_get_penalty(int irq)
}
if (irq < ACPI_MAX_ISA_IRQS)
- return penalty + acpi_isa_irq_penalty[irq];
+ return penalty + acpi_irq_penalty[irq];
penalty += acpi_irq_pci_sharing_penalty(irq);
return penalty;
@@ -538,14 +539,14 @@ int __init acpi_irq_penalty_init(void)
for (i = 0; i < link->irq.possible_count; i++) {
if (link->irq.possible[i] < ACPI_MAX_ISA_IRQS)
- acpi_isa_irq_penalty[link->irq.
+ acpi_irq_penalty[link->irq.
possible[i]] +=
penalty;
}
} else if (link->irq.active &&
- (link->irq.active < ACPI_MAX_ISA_IRQS)) {
- acpi_isa_irq_penalty[link->irq.active] +=
+ (link->irq.active < ACPI_MAX_IRQS)) {
+ acpi_irq_penalty[link->irq.active] +=
PIRQ_PENALTY_PCI_POSSIBLE;
}
}
@@ -828,7 +829,7 @@ static void acpi_pci_link_remove(struct acpi_device *device)
}
/*
- * modify acpi_isa_irq_penalty[] from cmdline
+ * modify acpi_irq_penalty[] from cmdline
*/
static int __init acpi_irq_penalty_update(char *str, int used)
{
@@ -837,24 +838,24 @@ static int __init acpi_irq_penalty_update(char *str, int used)
for (i = 0; i < 16; i++) {
int retval;
int irq;
- int new_penalty;
retval = get_option(&str, &irq);
if (!retval)
break; /* no number found */
- /* see if this is a ISA IRQ */
- if ((irq < 0) || (irq >= ACPI_MAX_ISA_IRQS))
+ if (irq < 0)
+ continue;
+
+ if (irq >= ARRAY_SIZE(acpi_irq_penalty))
continue;
if (used)
- new_penalty = acpi_irq_get_penalty(irq) +
- PIRQ_PENALTY_ISA_USED;
+ acpi_irq_penalty[irq] = acpi_irq_get_penalty(irq) +
+ PIRQ_PENALTY_ISA_USED;
else
- new_penalty = 0;
+ acpi_irq_penalty[irq] = 0;
- acpi_isa_irq_penalty[irq] = new_penalty;
if (retval != 2) /* no next number */
break;
}
@@ -870,14 +871,14 @@ static int __init acpi_irq_penalty_update(char *str, int used)
*/
void acpi_penalize_isa_irq(int irq, int active)
{
- if ((irq >= 0) && (irq < ARRAY_SIZE(acpi_isa_irq_penalty)))
- acpi_isa_irq_penalty[irq] = acpi_irq_get_penalty(irq) +
- (active ? PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING);
+ if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty))
+ acpi_irq_penalty[irq] = acpi_irq_get_penalty(irq) +
+ (active ? PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING);
}
bool acpi_isa_irq_available(int irq)
{
- return irq >= 0 && (irq >= ARRAY_SIZE(acpi_isa_irq_penalty) ||
+ return irq >= 0 && (irq >= ARRAY_SIZE(acpi_irq_penalty) ||
acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
}
--
1.9.1
^ permalink raw reply related
* [PATCH 0/4] ARM: davinci: Remove DMA resources for MMC/SPI
From: Sekhar Nori @ 2016-10-01 17:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160928103530.15291-1-peter.ujfalusi@ti.com>
On Wednesday 28 September 2016 04:05 PM, Peter Ujfalusi wrote:
> Hi,
>
> The drivers for davinci MMC and SPI have been converted to the new DMAengine API
> and no longer rely on the IORESOURCE_DMA.
> This is the case for at least one release cycle so now we can remove the
> IORESOURCE_DMA for these devices.
Hi Peter, applied to v4.10/cleanup branch of my tree. Thanks!
~Sekhar
^ permalink raw reply
* [RFC] arm64: Enforce observed order for spinlock and data
From: bdegraaf at codeaurora.org @ 2016-10-01 16:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160930193231.GA2521@remoulade>
On 2016-09-30 15:32, Mark Rutland wrote:
> On Fri, Sep 30, 2016 at 01:40:57PM -0400, Brent DeGraaf wrote:
>> Prior spinlock code solely used load-acquire and store-release
>> semantics to ensure ordering of the spinlock lock and the area it
>> protects. However, store-release semantics and ordinary stores do
>> not protect against accesses to the protected area being observed
>> prior to the access that locks the lock itself.
>>
>> While the load-acquire and store-release ordering is sufficient
>> when the spinlock routines themselves are strictly used, other
>> kernel code that references the lock values directly (e.g. lockrefs)
>> could observe changes to the area protected by the spinlock prior
>> to observance of the lock itself being in a locked state, despite
>> the fact that the spinlock logic itself is correct.
>
> If the spinlock logic is correct, why are we changing that, and not the
> lockref
> code that you say has a problem?
>
> What exactly goes wrong in the lockref code? Can you give a concrete
> example?
>
> Why does the lockref code accesses lock-protected fields without taking
> the
> lock first? Wouldn't concurrent modification be a problem regardless?
>
>> + /*
>> + * Yes: The store done on this cpu was the one that locked the lock.
>> + * Store-release one-way barrier on LL/SC means that accesses coming
>> + * after this could be reordered into the critical section of the
>
> I assume you meant s/store-release/load-acquire/ here. This does not
> make sense
> to me otherwise.
>
>> + * load-acquire/store-release, where we did not own the lock. On
>> LSE,
>> + * even the one-way barrier of the store-release semantics is
>> missing,
>
> Likewise (for the LSE case description).
>
>> + * so LSE needs an explicit barrier here as well. Without this, the
>> + * changed contents of the area protected by the spinlock could be
>> + * observed prior to the lock.
>> + */
>
> By whom? We generally expect that if data is protected by a lock, you
> take the
> lock before accessing it. If you expect concurrent lockless readers,
> then
> there's a requirement on the writer side to explicitly provide the
> ordering it
> requires -- spinlocks are not expected to provide that.
More details are in my response to Robin, but there is an API arm64
supports
in spinlock.h which is used by lockref to determine whether a lock is
free or not.
For that code to work properly without adding these barriers, that API
needs to
take the lock. I tested that configuration, and it cost us heavily in
terms of
lockref performance in the form of a 30 to 50 percent performance loss.
On the
other hand, I have not seen any performance degradation due to the
introduction
of these barriers.
>
> So, why aren't those observers taking the lock?
lockref doesn't take the lock specifically because it is slower.
>
> What pattern of accesses are made by readers and writers such that
> there is a
> problem?
I added the barriers to the readers/writers because I do not know these
are not
similarly abused. There is a lot of driver code out there, and ensuring
order is
the safest way to be sure we don't get burned by something similar to
the lockref
access.
>
> What does this result in?
>
No measureable negative performance impact. However, the lockref
performance actually
improved slightly (between 1 and 2 percent on my 24-core test system)
due to the change.
>> +" dmb ish\n"
>> +" b 3f\n"
>> +"4:\n"
>> /*
>> * No: spin on the owner. Send a local event to avoid missing an
>> * unlock before the exclusive load.
>> @@ -116,7 +129,15 @@ static inline void arch_spin_lock(arch_spinlock_t
>> *lock)
>> " ldaxrh %w2, %4\n"
>> " eor %w1, %w2, %w0, lsr #16\n"
>> " cbnz %w1, 2b\n"
>> - /* We got the lock. Critical section starts here. */
>> + /*
>> + * We got the lock and have observed the prior owner's
>> store-release.
>> + * In this case, the one-way barrier of the prior owner that we
>> + * observed combined with the one-way barrier of our load-acquire is
>> + * enough to ensure accesses to the protected area coming after this
>> + * are not accessed until we own the lock. In this case, other
>> + * observers will not see our changes prior to observing the lock
>> + * itself. Critical locked section starts here.
>> + */
>
> Each of these comments ends up covers, and their repeated presence
> makes the
> code harder to read. If there's a common problem, note it once at the
> top of
> the file.
I added these comments to make it crystal clear that the absence of a
barrier at this
point was deliberate, and that I did consider each code path.
>
> Thanks,
> Mark.
^ permalink raw reply
* [RFC] arm64: Enforce observed order for spinlock and data
From: bdegraaf at codeaurora.org @ 2016-10-01 15:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160930190535.GB3142@twins.programming.kicks-ass.net>
On 2016-09-30 15:05, Peter Zijlstra wrote:
> On Fri, Sep 30, 2016 at 01:40:57PM -0400, Brent DeGraaf wrote:
>> Prior spinlock code solely used load-acquire and store-release
>> semantics to ensure ordering of the spinlock lock and the area it
>> protects. However, store-release semantics and ordinary stores do
>> not protect against accesses to the protected area being observed
>> prior to the access that locks the lock itself.
>>
>> While the load-acquire and store-release ordering is sufficient
>> when the spinlock routines themselves are strictly used, other
>> kernel code that references the lock values directly (e.g. lockrefs)
>
> Isn't the problem with lockref the fact that arch_spin_value_unlocked()
> isn't a load-acquire, and therefore the CPU in question doesn't need to
> observe the contents of the critical section etc..?
>
> That is, wouldn't fixing arch_spin_value_unlocked() by making that an
> smp_load_acquire() fix things much better?
>
>> could observe changes to the area protected by the spinlock prior
>> to observance of the lock itself being in a locked state, despite
>> the fact that the spinlock logic itself is correct.
Thanks for your comments.
The load-acquire would not be enough for lockref, as it can still
observe
the changed data out of order. To ensure order, lockref has to take the
lock, which comes at a high performance cost. Turning off the config
option CONFIG_ARCH_USE_CMPXCHG_LOCKREF, which forces arch_spin_lock
calls
reduced my multicore performance between 30 and 50 percent using Linus'
"stat" test that was part of the grounds for introducing lockref.
On the other hand, I did not see any negative impact to performance by
the new barriers, in large part probably because they only tend to come
into play when locks are not heavily contended in the case of ticket
locks.
I have not yet found any other spinlock "abuses" in the kernel besides
lockref, but locks are referenced in a large number of places that
includes drivers, which are dynamic. It is arguable that I could remove
the barriers to the read/write locks, as lockref doesn't use those, but
it seemed to me to be safer and more "normal" to ensure that the locked
write to the lock itself is visible prior to the changed contents of the
protected area.
Brent
^ permalink raw reply
* [RFC] arm64: Enforce observed order for spinlock and data
From: bdegraaf at codeaurora.org @ 2016-10-01 15:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <61567858-7224-c7af-5207-3872671b58ad@arm.com>
On 2016-09-30 14:43, Robin Murphy wrote:
>> + * so LSE needs an explicit barrier here as well. Without this, the
>> + * changed contents of the area protected by the spinlock could be
>> + * observed prior to the lock.
>
> What is that last sentence supposed to mean? If the lock is free, then
> surely any previous writes to the data it's protecting would have
> already been observed by the release semantics of the previous unlock?
> If the lock is currently held, what do we care about the state of the
> data while we're still spinning on the lock itself? And if someone's
> touching the data without having acquired *or* released the lock, why
> is
> there a lock in the first place?
>
> This seems like a very expensive way of papering over broken callers :/
>
> Robin.
>
Thanks for your question.
First off, I saw no negative impact to performance as a result of
introducing
these barriers running a wide variety of use cases, both for mobile and
server-class devices ranging from 4 to 24 cpus.
Yes, it does protect lockref, which observes the spinlocks in a
non-conventional
way. In fact, with this code in place, the performance of Linus' test
which runs
stat like crazy actually improved in the range of 1-2% (I suspect this
is due to
fewer failures due to contention on the protected count lockref uses).
The lockref code can be made compliant, but not by a single
load-acquire--it has
to take the lock. Turning off CONFIG_ARCH_USE_CMPXCHG_LOCKREF is the
most
obvious solution as it forces lockref.c to take the lock. That,
however, comes
at a very high performance cost: 30-50% on Linus' stat test on a 24-core
system.
For larger systems, this performance gap will get even worse.
With the above in mind, it seems that supporting lockref's unorthodox
method of
dealing with the lock is the better alternative, as it helps, rather
than hurts,
arm64 performance.
Brent
^ permalink raw reply
* [PATCH V4 05/10] dmaengine: qcom_hidma: make pending_tre_count atomic
From: Sinan Kaya @ 2016-10-01 15:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001061906.GG2467@localhost>
On 10/1/2016 2:19 AM, Vinod Koul wrote:
>> Making it atomic so that it can be updated from multiple contexts.
> How is it multiple contexts? It's either existing context of MSI, not both!
>
I was trying to mean multiple processor contexts here. The driver allocates 11
MSI interrupts. Each MSI interrupt can be assigned to a different CPU. Then,
we have a race condition for common variables as they share the same interrupt
handler with a different cause bit.
I will put the above description into the commit text.
--
Sinan Kaya
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH V4 04/10] dmaengine: qcom_hidma: configure DMA and MSI for OF
From: Sinan Kaya @ 2016-10-01 15:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001061710.GF2467@localhost>
On 10/1/2016 2:17 AM, Vinod Koul wrote:
> On Wed, Sep 28, 2016 at 10:12:41PM -0400, Sinan Kaya wrote:
>> Configure the DMA bindings for the device tree based firmware.
>>
>> Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
>> ---
>> drivers/dma/qcom/hidma_mgmt.c | 5 ++++-
>> 1 file changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c
>> index 82f36e4..e8f6b84 100644
>> --- a/drivers/dma/qcom/hidma_mgmt.c
>> +++ b/drivers/dma/qcom/hidma_mgmt.c
>> @@ -375,8 +375,11 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np)
>> ret = PTR_ERR(new_pdev);
>> goto out;
>> }
>> + of_node_get(child);
>> + new_pdev->dev.of_node = child;
>> of_dma_configure(&new_pdev->dev, child);
>> -
>> + of_msi_configure(&new_pdev->dev, child);
>> + of_node_put(child);
>
> should this be done unconditionally? Dont we needto call this only for
> platforms with msi?
I followed the pattern in of_platform_device_create_pdata function. of_msi_configure does
nothing if MSI is not enabled as irq_find_matching_host returns NULL. It didn't have any
side effects on my testing either.
>
>> kfree(res);
>> res = NULL;
>> }
>> --
>> 1.9.1
>>
>
--
Sinan Kaya
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH] ARM: dts: rockchip: Reserve unusable memory region on rk3066
From: =?UTF-8?q?Pawe=C5=82=20Jarosz?= @ 2016-10-01 14:09 UTC (permalink / raw)
To: linux-arm-kernel
For some reason accessing memory region above 0xfe000000 freezes
system on rk3066. There is similiar bug on later rockchip soc (rk3288)
solved same way.
Signed-off-by: Pawe? Jarosz <paweljarosz3691@gmail.com>
---
arch/arm/boot/dts/rk3066a.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
index 0d0dae3..44c8956 100644
--- a/arch/arm/boot/dts/rk3066a.dtsi
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -93,6 +93,19 @@
};
};
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ /*
+ * The rk3066 cannot use the memory area above 0x9F000000
+ * for some unknown reason.
+ */
+ unusable at 9F000000 {
+ reg = <0x9F000000 0x1000000>;
+ };
+ };
+
i2s0: i2s at 10118000 {
compatible = "rockchip,rk3066-i2s";
reg = <0x10118000 0x2000>;
--
2.7.4
^ permalink raw reply related
* [PATCH 5/6] ARM: davinci: enable the LCDC DRM driver in defconfig
From: Sekhar Nori @ 2016-10-01 12:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475166715-7857-6-git-send-email-bgolaszewski@baylibre.com>
On Thursday 29 September 2016 10:01 PM, Bartosz Golaszewski wrote:
> With the device tree changes for tilcdc in place, we can now enable
> the driver by default in the davinci_all defconfig file.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Applied to v4.10/defconfig branch of my tree. Adjusted the subject line
to be consistent with how patches for defconfig are usually headlines.
ARM: davinci_all_defconfig: enable LCDC DRM driver
defconfig updates are last in the pull request I will send up, so the
description will make sense when finally merged.
Thanks,
Sekhar
^ permalink raw reply
* [PATCH v3 3/3] phy: meson: add USB2 PHY support for Meson8b and GXBB
From: Martin Blumenstingl @ 2016-10-01 12:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001121900.1168-1-martin.blumenstingl@googlemail.com>
This is a new driver for the USB PHY found in Meson8b and GXBB SoCs.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Tested-by: Kevin Hilman <khilman@baylibre.com>
---
drivers/phy/Kconfig | 13 ++
drivers/phy/Makefile | 1 +
drivers/phy/phy-meson8b-usb2.c | 284 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 298 insertions(+)
create mode 100644 drivers/phy/phy-meson8b-usb2.c
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 19bff3a..b0c8135 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -453,4 +453,17 @@ config PHY_NS2_PCIE
help
Enable this to support the Broadcom Northstar2 PCIe PHY.
If unsure, say N.
+
+config PHY_MESON8B_USB2
+ tristate "Meson8b and GXBB USB2 PHY driver"
+ default ARCH_MESON
+ depends on OF && (ARCH_MESON || COMPILE_TEST)
+ depends on USB_SUPPORT
+ select USB_COMMON
+ select GENERIC_PHY
+ help
+ Enable this to support the Meson USB2 PHYs found in Meson8b
+ and GXBB SoCs.
+ If unsure, say N.
+
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 90ae198..5649473 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
+obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
diff --git a/drivers/phy/phy-meson8b-usb2.c b/drivers/phy/phy-meson8b-usb2.c
new file mode 100644
index 0000000..73bf632
--- /dev/null
+++ b/drivers/phy/phy-meson8b-usb2.c
@@ -0,0 +1,284 @@
+/*
+ * Meson8b and GXBB USB2 PHY driver
+ *
+ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/usb/of.h>
+
+#define REG_CONFIG 0x00
+ #define REG_CONFIG_CLK_EN BIT(0)
+ #define REG_CONFIG_CLK_SEL_MASK GENMASK(3, 1)
+ #define REG_CONFIG_CLK_DIV_MASK GENMASK(10, 4)
+ #define REG_CONFIG_CLK_32k_ALTSEL BIT(15)
+ #define REG_CONFIG_TEST_TRIG BIT(31)
+
+#define REG_CTRL 0x04
+ #define REG_CTRL_SOFT_PRST BIT(0)
+ #define REG_CTRL_SOFT_HRESET BIT(1)
+ #define REG_CTRL_SS_SCALEDOWN_MODE_MASK GENMASK(3, 2)
+ #define REG_CTRL_CLK_DET_RST BIT(4)
+ #define REG_CTRL_INTR_SEL BIT(5)
+ #define REG_CTRL_CLK_DETECTED BIT(8)
+ #define REG_CTRL_SOF_SENT_RCVD_TGL BIT(9)
+ #define REG_CTRL_SOF_TOGGLE_OUT BIT(10)
+ #define REG_CTRL_POWER_ON_RESET BIT(15)
+ #define REG_CTRL_SLEEPM BIT(16)
+ #define REG_CTRL_TX_BITSTUFF_ENN_H BIT(17)
+ #define REG_CTRL_TX_BITSTUFF_ENN BIT(18)
+ #define REG_CTRL_COMMON_ON BIT(19)
+ #define REG_CTRL_REF_CLK_SEL_MASK GENMASK(21, 20)
+ #define REG_CTRL_REF_CLK_SEL_SHIFT 20
+ #define REG_CTRL_FSEL_MASK GENMASK(24, 22)
+ #define REG_CTRL_FSEL_SHIFT 22
+ #define REG_CTRL_PORT_RESET BIT(25)
+ #define REG_CTRL_THREAD_ID_MASK GENMASK(31, 26)
+
+#define REG_ENDP_INTR 0x08
+
+/* bits [31:26], [24:21] and [15:3] seem to be read-only */
+#define REG_ADP_BC 0x0c
+ #define REG_ADP_BC_VBUS_VLD_EXT_SEL BIT(0)
+ #define REG_ADP_BC_VBUS_VLD_EXT BIT(1)
+ #define REG_ADP_BC_OTG_DISABLE BIT(2)
+ #define REG_ADP_BC_ID_PULLUP BIT(3)
+ #define REG_ADP_BC_DRV_VBUS BIT(4)
+ #define REG_ADP_BC_ADP_PRB_EN BIT(5)
+ #define REG_ADP_BC_ADP_DISCHARGE BIT(6)
+ #define REG_ADP_BC_ADP_CHARGE BIT(7)
+ #define REG_ADP_BC_SESS_END BIT(8)
+ #define REG_ADP_BC_DEVICE_SESS_VLD BIT(9)
+ #define REG_ADP_BC_B_VALID BIT(10)
+ #define REG_ADP_BC_A_VALID BIT(11)
+ #define REG_ADP_BC_ID_DIG BIT(12)
+ #define REG_ADP_BC_VBUS_VALID BIT(13)
+ #define REG_ADP_BC_ADP_PROBE BIT(14)
+ #define REG_ADP_BC_ADP_SENSE BIT(15)
+ #define REG_ADP_BC_ACA_ENABLE BIT(16)
+ #define REG_ADP_BC_DCD_ENABLE BIT(17)
+ #define REG_ADP_BC_VDAT_DET_EN_B BIT(18)
+ #define REG_ADP_BC_VDAT_SRC_EN_B BIT(19)
+ #define REG_ADP_BC_CHARGE_SEL BIT(20)
+ #define REG_ADP_BC_CHARGE_DETECT BIT(21)
+ #define REG_ADP_BC_ACA_PIN_RANGE_C BIT(22)
+ #define REG_ADP_BC_ACA_PIN_RANGE_B BIT(23)
+ #define REG_ADP_BC_ACA_PIN_RANGE_A BIT(24)
+ #define REG_ADP_BC_ACA_PIN_GND BIT(25)
+ #define REG_ADP_BC_ACA_PIN_FLOAT BIT(26)
+
+#define REG_DBG_UART 0x14
+
+#define REG_TEST 0x18
+ #define REG_TEST_DATA_IN_MASK GENMASK(3, 0)
+ #define REG_TEST_EN_MASK GENMASK(7, 4)
+ #define REG_TEST_ADDR_MASK GENMASK(11, 8)
+ #define REG_TEST_DATA_OUT_SEL BIT(12)
+ #define REG_TEST_CLK BIT(13)
+ #define REG_TEST_VA_TEST_EN_B_MASK GENMASK(15, 14)
+ #define REG_TEST_DATA_OUT_MASK GENMASK(19, 16)
+ #define REG_TEST_DISABLE_ID_PULLUP BIT(20)
+
+#define REG_TUNE 0x1c
+ #define REG_TUNE_TX_RES_TUNE_MASK GENMASK(1, 0)
+ #define REG_TUNE_TX_HSXV_TUNE_MASK GENMASK(3, 2)
+ #define REG_TUNE_TX_VREF_TUNE_MASK GENMASK(7, 4)
+ #define REG_TUNE_TX_RISE_TUNE_MASK GENMASK(9, 8)
+ #define REG_TUNE_TX_PREEMP_PULSE_TUNE BIT(10)
+ #define REG_TUNE_TX_PREEMP_AMP_TUNE_MASK GENMASK(12, 11)
+ #define REG_TUNE_TX_FSLS_TUNE_MASK GENMASK(16, 13)
+ #define REG_TUNE_SQRX_TUNE_MASK GENMASK(19, 17)
+ #define REG_TUNE_OTG_TUNE GENMASK(22, 20)
+ #define REG_TUNE_COMP_DIS_TUNE GENMASK(25, 23)
+ #define REG_TUNE_HOST_DM_PULLDOWN BIT(26)
+ #define REG_TUNE_HOST_DP_PULLDOWN BIT(27)
+
+#define RESET_COMPLETE_TIME 500
+#define ACA_ENABLE_COMPLETE_TIME 50
+
+struct phy_meson8b_usb2_priv {
+ void __iomem *regs;
+ enum usb_dr_mode dr_mode;
+ struct clk *clk_usb_general;
+ struct clk *clk_usb;
+ struct reset_control *reset;
+};
+
+static u32 phy_meson8b_usb2_read(struct phy_meson8b_usb2_priv *phy_priv,
+ u32 reg)
+{
+ return readl(phy_priv->regs + reg);
+}
+
+static void phy_meson8b_usb2_mask_bits(struct phy_meson8b_usb2_priv *phy_priv,
+ u32 reg, u32 mask, u32 value)
+{
+ u32 data;
+
+ data = phy_meson8b_usb2_read(phy_priv, reg);
+ data &= ~mask;
+ data |= (value & mask);
+
+ writel(data, phy_priv->regs + reg);
+}
+
+static int phy_meson8b_usb2_power_on(struct phy *phy)
+{
+ struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
+ int ret;
+
+ if (!IS_ERR_OR_NULL(priv->reset)) {
+ ret = reset_control_reset(priv->reset);
+ if (ret) {
+ dev_err(&phy->dev, "Failed to trigger USB reset\n");
+ return ret;
+ }
+ }
+
+ ret = clk_prepare_enable(priv->clk_usb_general);
+ if (ret) {
+ dev_err(&phy->dev, "Failed to enable USB general clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(priv->clk_usb);
+ if (ret) {
+ dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
+ return ret;
+ }
+
+ phy_meson8b_usb2_mask_bits(priv, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL,
+ REG_CONFIG_CLK_32k_ALTSEL);
+
+ phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_REF_CLK_SEL_MASK,
+ 0x2 << REG_CTRL_REF_CLK_SEL_SHIFT);
+
+ phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_FSEL_MASK,
+ 0x5 << REG_CTRL_FSEL_SHIFT);
+
+ /* reset the PHY */
+ phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_POWER_ON_RESET,
+ REG_CTRL_POWER_ON_RESET);
+ udelay(RESET_COMPLETE_TIME);
+ phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_POWER_ON_RESET, 0);
+ udelay(RESET_COMPLETE_TIME);
+
+ phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT,
+ REG_CTRL_SOF_TOGGLE_OUT);
+
+ if (priv->dr_mode == USB_DR_MODE_HOST) {
+ phy_meson8b_usb2_mask_bits(priv, REG_ADP_BC,
+ REG_ADP_BC_ACA_ENABLE,
+ REG_ADP_BC_ACA_ENABLE);
+
+ udelay(ACA_ENABLE_COMPLETE_TIME);
+
+ if (phy_meson8b_usb2_read(priv, REG_ADP_BC) &
+ REG_ADP_BC_ACA_PIN_FLOAT) {
+ dev_warn(&phy->dev, "USB ID detect failed!\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int phy_meson8b_usb2_power_off(struct phy *phy)
+{
+ struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
+
+ clk_disable_unprepare(priv->clk_usb);
+ clk_disable_unprepare(priv->clk_usb_general);
+
+ return 0;
+}
+
+static const struct phy_ops phy_meson8b_usb2_ops = {
+ .power_on = phy_meson8b_usb2_power_on,
+ .power_off = phy_meson8b_usb2_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int phy_meson8b_usb2_probe(struct platform_device *pdev)
+{
+ struct phy_meson8b_usb2_priv *priv;
+ struct resource *res;
+ struct phy *phy;
+ struct phy_provider *phy_provider;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->regs))
+ return PTR_ERR(priv->regs);
+
+ priv->clk_usb_general = devm_clk_get(&pdev->dev, "usb_general");
+ if (IS_ERR(priv->clk_usb_general))
+ return PTR_ERR(priv->clk_usb_general);
+
+ priv->clk_usb = devm_clk_get(&pdev->dev, "usb");
+ if (IS_ERR(priv->clk_usb))
+ return PTR_ERR(priv->clk_usb);
+
+ priv->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
+ NULL);
+ if (PTR_ERR(priv->reset) == -EPROBE_DEFER)
+ return PTR_ERR(priv->reset);
+
+ priv->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node, -1);
+ if (priv->dr_mode == USB_DR_MODE_UNKNOWN) {
+ dev_err(&pdev->dev,
+ "missing dual role configuration of the controller\n");
+ return -EINVAL;
+ }
+
+ phy = devm_phy_create(&pdev->dev, NULL, &phy_meson8b_usb2_ops);
+ if (IS_ERR(phy)) {
+ dev_err(&pdev->dev, "failed to create PHY\n");
+ return PTR_ERR(phy);
+ }
+
+ phy_set_drvdata(phy, priv);
+
+ phy_provider =
+ devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id phy_meson8b_usb2_of_match[] = {
+ { .compatible = "amlogic,meson8b-usb2-phy", },
+ { .compatible = "amlogic,meson-gxbb-usb2-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, phy_meson8b_usb2_of_match);
+
+static struct platform_driver phy_meson8b_usb2_driver = {
+ .probe = phy_meson8b_usb2_probe,
+ .driver = {
+ .name = "phy-meson-usb2",
+ .of_match_table = phy_meson8b_usb2_of_match,
+ },
+};
+module_platform_driver(phy_meson8b_usb2_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_DESCRIPTION("Meson8b and GXBB USB2 PHY driver");
+MODULE_LICENSE("GPL");
--
2.10.0
^ permalink raw reply related
* [PATCH v3 2/3] Documentation: dt-bindings: rename meson-usb2-phy to meson8b-usb2-phy
From: Martin Blumenstingl @ 2016-10-01 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001121900.1168-1-martin.blumenstingl@googlemail.com>
The corresponding driver only supports the USB PHY on Meson8b and GXBB
SoCs. Newer SoC versions are using a different USB PHY implementation,
which will mean that a new driver is required. Thus make sure that our
naming is specific enough so it does not conflict with upcoming drivers.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../bindings/phy/{meson-usb2-phy.txt => meson8b-usb2-phy.txt} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename Documentation/devicetree/bindings/phy/{meson-usb2-phy.txt => meson8b-usb2-phy.txt} (95%)
diff --git a/Documentation/devicetree/bindings/phy/meson-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson8b-usb2-phy.txt
similarity index 95%
rename from Documentation/devicetree/bindings/phy/meson-usb2-phy.txt
rename to Documentation/devicetree/bindings/phy/meson8b-usb2-phy.txt
index bc616c1..5fa73b9 100644
--- a/Documentation/devicetree/bindings/phy/meson-usb2-phy.txt
+++ b/Documentation/devicetree/bindings/phy/meson8b-usb2-phy.txt
@@ -1,4 +1,4 @@
-* Amlogic USB2 PHY
+* Amlogic Meson8b and GXBB USB2 PHY
Required properties:
- compatible: Depending on the platform this should be one of:
--
2.10.0
^ permalink raw reply related
* [PATCH v3 1/3] Documentation: dt-bindings: update the meson-usb2-phy example
From: Martin Blumenstingl @ 2016-10-01 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001121900.1168-1-martin.blumenstingl@googlemail.com>
Update the example so the node name uses a dash (instead of an
underscore) as per convention.
Additionally it updates the example register offset to a real example
(the old value was taken from a draft where there was an additional PHY
bus).
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
Documentation/devicetree/bindings/phy/meson-usb2-phy.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/phy/meson-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson-usb2-phy.txt
index 9da5ea2..bc616c1 100644
--- a/Documentation/devicetree/bindings/phy/meson-usb2-phy.txt
+++ b/Documentation/devicetree/bindings/phy/meson-usb2-phy.txt
@@ -16,10 +16,10 @@ Optional properties:
Example:
-usb0_phy: usb_phy at 0 {
+usb0_phy: usb-phy at c0000000 {
compatible = "amlogic,meson-gxbb-usb2-phy";
#phy-cells = <0>;
- reg = <0x0 0x0 0x0 0x20>;
+ reg = <0x0 0xc0000000 0x0 0x20>;
resets = <&reset RESET_USB_OTG>;
clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>;
clock-names = "usb_general", "usb";
--
2.10.0
^ permalink raw reply related
* [PATCH v3 0/3] usb/phy: Add Amlogic Meson8b and GXBB USB support
From: Martin Blumenstingl @ 2016-10-01 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160904213152.25837-1-martin.blumenstingl@googlemail.com>
This series adds initial support for the DWC2 USB controllers and Meson
specific USB PHYs found in Meson8b and GXBB SoCs, which means:
- new DWC2 bindings and platform specific core configuration
- a PHY driver supporting the USB2 PHY on Meson8b and GXBB SoCs
The first DWC2 controller is usually configured in OTG mode, whereas
the second DWC2 controller is usually configured in host(-only) mode.
Unfortunately no (public) datasheet is available and the reference PHY
driver does not contain comments or speaking register name definitions.
The nice people from BayLibre have already requested the datasheets
(currently we can for example only guess that there is a mux clock
inside the PHY, but we don't know it's parents).
With this series both DWC2 controllers are configure in host mode,
because the reference driver polls some of the PHY registers in OTG
mode and then re-configures the dwc2 driver instance accordingly (if
anyone is interested, this is the relevant piece of code: [0]). This
seems good enough for the beginning though.
Changes since v2:
- integrated a patch from Axel Lin to add the USB_SUPPORT dependency
- renamed driver (Kconfig, source and docs) to phy-meson8b-usb2 as the
driver is only compatible with the USB2 PHY found on Meson8b and GXBB
(newer SoC versions are using a different USB PHY and I could not
find anything that the Meson8b / GXBB and GXL / GXM USB PHYs have in
common)
- switch from device_reset_optional to reset_control_reset and move
this call to phy_meson8b_usb2_power_on. This will allow us to simply
switch to devm_reset_control_get_optional_shared in the future, once
the reset control supports reset pulses for shared reset lines
- updated documentation example (use dash instead of unserscore in node
name and use a better reg example)
- dropped the following patches as they were accepted upstream (the
only patch which remains from the original series is the actual PHY
driver):
- "usb: dwc2: add support for Meson8b and GXBB SoCs" (f94310ac076e in
arm-soc.git/next/late)
- "Documentation: dt-bindings: Add documentation for the Meson USB2
PHYs" (c940d7658de0 in arm-soc.git/next/late)
- "ARM64: meson-gxbb: add USB Nodes" (566603e5e6b6 in
arm-soc.git/next/late)
- "ARM64: meson-gxbb-p20x: Enable USB Nodes" (8735053d7968 in
arm-soc.git/next/late)
- "ARM64: meson-gxbb-vega-s95: Enable USB Nodes" (c763eb82a01d in
arm-soc.git/next/late)
Changes since v1:
- the patch "clk: gxbb: expose USB clocks" was not sent again as it was
already applied by Kevin Hilman (thanks!)
- dropped (unnecessary) USB PHY bus from .dts
- remove underscores from PHY node names in .dts
- rename the dwc2 nodes in the .dts to usb (as per convention)
- remove unused struct reset_control from phy_meson_usb2_priv
- removed refcounting "reset" workaround and only specify the reset for
the first PHY in the .dts (Jerome has reported that his boards don't
need the explicit reset, while my board needs it). In addition (to
make this work) the driver now treats the reset as optional
- use the RESET_USB_OTG definition (from
<dt-bindings/reset/amlogic,meson-gxbb-reset.h>) instead of a magic
number in the .dts
[0] https://github.com/150balbes/Amlogic_s905-kernel/blob/master/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.c#L642
Martin Blumenstingl (3):
Documentation: dt-bindings: update the meson-usb2-phy example
Documentation: dt-bindings: rename meson-usb2-phy to meson8b-usb2-phy
phy: meson: add USB2 PHY support for Meson8b and GXBB
.../{meson-usb2-phy.txt => meson8b-usb2-phy.txt} | 6 +-
drivers/phy/Kconfig | 13 +
drivers/phy/Makefile | 1 +
drivers/phy/phy-meson8b-usb2.c | 284 +++++++++++++++++++++
4 files changed, 301 insertions(+), 3 deletions(-)
rename Documentation/devicetree/bindings/phy/{meson-usb2-phy.txt => meson8b-usb2-phy.txt} (87%)
create mode 100644 drivers/phy/phy-meson8b-usb2.c
--
2.10.0
^ permalink raw reply
* [PATCH RFC v2 0/12] Add R8A7743/SK-RZG1M board support
From: Geert Uytterhoeven @ 2016-10-01 11:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1987532.PE2ex6PrJ5@wasted.cogentembedded.com>
Hi Sergei,
On Fri, Sep 30, 2016 at 12:14 AM, Sergei Shtylyov
<sergei.shtylyov@cogentembedded.com> wrote:
> Here's the set of 12 patches against Simon Horman's 'renesas.git' repo,
> 'renesas-devel-20160926-v4.8-rc8' tag. I'm adding the device tree support for
> the R8A7743-based SK-RZG1M board. The SoC is close to R8A7791 and the board
> seems identical to the R8A7791/Porter board. This version includes the Ether,
> so the board should boot with NFS root now. I tried to address all the comments
> to the version 1 (except the need to use the new CPG/MSSR drivers -- this one
> will be addressed RSN). The DMAC/SCIF/IRQC bindings patches posted recently are
There's an (old) version of an r8a7791 CPG/MSSR driver at
https://git.kernel.org/cgit/linux/kernel/git/geert/renesas-drivers.git/log/?h=topic/cpg-mssr-v4
To handle it cleanly, this is going to need "[PATCH/RFC v3 00/22] soc:
renesas: Add R-Car RST driver for obtaining mode pin state"...
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH v2 6/6] arm: dts: imx7-colibri: Use enable-gpios for BL_ON
From: Bhuvanchandra DV @ 2016-10-01 10:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001101235.24598-1-bhuvanchandra.dv@toradex.com>
Use pwm-backlight driver 'enable-gpios' property for backlight on/off control.
Signed-off-by: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com>
---
arch/arm/boot/dts/imx7-colibri.dtsi | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi
index 2af5e3e..ce5edb5 100644
--- a/arch/arm/boot/dts/imx7-colibri.dtsi
+++ b/arch/arm/boot/dts/imx7-colibri.dtsi
@@ -43,7 +43,10 @@
/ {
bl: backlight {
compatible = "pwm-backlight";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_bl_on>;
pwms = <&pwm1 0 5000000 0>;
+ enable-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
};
reg_module_3v3: regulator-module-3v3 {
@@ -356,7 +359,6 @@
fsl,pins = <
MX7D_PAD_ECSPI2_SS0__GPIO4_IO23 0x14 /* SODIMM 65 */
MX7D_PAD_SD1_CD_B__GPIO5_IO0 0x14 /* SODIMM 69 */
- MX7D_PAD_SD1_WP__GPIO5_IO1 0x14 /* SODIMM 71 */
MX7D_PAD_I2C4_SDA__GPIO4_IO15 0x14 /* SODIMM 75 */
MX7D_PAD_ECSPI1_MISO__GPIO4_IO18 0x14 /* SODIMM 79 */
MX7D_PAD_I2C3_SCL__GPIO4_IO12 0x14 /* SODIMM 81 */
@@ -388,6 +390,12 @@
>;
};
+ pinctrl_gpio_bl_on: gpio-bl-on {
+ fsl,pins = <
+ MX7D_PAD_SD1_WP__GPIO5_IO1 0x14
+ >;
+ };
+
pinctrl_i2c1_int: i2c1-int-grp { /* PMIC / TOUCH */
fsl,pins = <
MX7D_PAD_GPIO1_IO13__GPIO1_IO13 0x79
--
2.9.2
^ permalink raw reply related
* [PATCH v2 5/6] arm: dts: imx7-colibri: Use pwm polarity control
From: Bhuvanchandra DV @ 2016-10-01 10:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001101235.24598-1-bhuvanchandra.dv@toradex.com>
Configure PWM polarity control.
Signed-off-by: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com>
---
arch/arm/boot/dts/imx7-colibri.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi
index a9cc657..2af5e3e 100644
--- a/arch/arm/boot/dts/imx7-colibri.dtsi
+++ b/arch/arm/boot/dts/imx7-colibri.dtsi
@@ -43,7 +43,7 @@
/ {
bl: backlight {
compatible = "pwm-backlight";
- pwms = <&pwm1 0 5000000>;
+ pwms = <&pwm1 0 5000000 0>;
};
reg_module_3v3: regulator-module-3v3 {
--
2.9.2
^ permalink raw reply related
* [PATCH v2 4/6] arm: dts: imx7: Update #pwm-cells for PWM polarity control
From: Bhuvanchandra DV @ 2016-10-01 10:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001101235.24598-1-bhuvanchandra.dv@toradex.com>
Update #pwm-cells to 3 in order to support PWM signal polarity control.
Signed-off-by: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com>
Acked-by: Rob Herring <robh@kernel.org>
---
arch/arm/boot/dts/imx7s.dtsi | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 0d7d5ac..8d1d471 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -601,7 +601,7 @@
clocks = <&clks IMX7D_PWM1_ROOT_CLK>,
<&clks IMX7D_PWM1_ROOT_CLK>;
clock-names = "ipg", "per";
- #pwm-cells = <2>;
+ #pwm-cells = <3>;
status = "disabled";
};
@@ -612,7 +612,7 @@
clocks = <&clks IMX7D_PWM2_ROOT_CLK>,
<&clks IMX7D_PWM2_ROOT_CLK>;
clock-names = "ipg", "per";
- #pwm-cells = <2>;
+ #pwm-cells = <3>;
status = "disabled";
};
@@ -623,7 +623,7 @@
clocks = <&clks IMX7D_PWM3_ROOT_CLK>,
<&clks IMX7D_PWM3_ROOT_CLK>;
clock-names = "ipg", "per";
- #pwm-cells = <2>;
+ #pwm-cells = <3>;
status = "disabled";
};
@@ -634,7 +634,7 @@
clocks = <&clks IMX7D_PWM4_ROOT_CLK>,
<&clks IMX7D_PWM4_ROOT_CLK>;
clock-names = "ipg", "per";
- #pwm-cells = <2>;
+ #pwm-cells = <3>;
status = "disabled";
};
--
2.9.2
^ permalink raw reply related
* [PATCH v2 3/6] pwm: imx: support output polarity inversion
From: Bhuvanchandra DV @ 2016-10-01 10:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001101235.24598-1-bhuvanchandra.dv@toradex.com>
From: Lothar Wassmann <LW@KARO-electronics.de>
The i.MX pwm unit on i.MX27 and newer SoCs provides a configurable output
polarity. This patch adds support to utilize this feature where available.
Signed-off-by: Lothar Wa?mann <LW@KARO-electronics.de>
Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Documentation/devicetree/bindings/pwm/imx-pwm.txt | 6 +--
drivers/pwm/pwm-imx.c | 51 +++++++++++++++++++++--
2 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
index e00c2e9..c61bdf8 100644
--- a/Documentation/devicetree/bindings/pwm/imx-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
@@ -6,8 +6,8 @@ Required properties:
- "fsl,imx1-pwm" for PWM compatible with the one integrated on i.MX1
- "fsl,imx27-pwm" for PWM compatible with the one integrated on i.MX27
- reg: physical base address and length of the controller's registers
-- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
- the cells format.
+- #pwm-cells: 2 for i.MX1 and 3 for i.MX27 and newer SoCs. See pwm.txt
+ in this directory for a description of the cells format.
- clocks : Clock specifiers for both ipg and per clocks.
- clock-names : Clock names should include both "ipg" and "per"
See the clock consumer binding,
@@ -17,7 +17,7 @@ See the clock consumer binding,
Example:
pwm1: pwm at 53fb4000 {
- #pwm-cells = <2>;
+ #pwm-cells = <3>;
compatible = "fsl,imx53-pwm", "fsl,imx27-pwm";
reg = <0x53fb4000 0x4000>;
clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>,
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index d600fd5..c37d223 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -38,6 +38,7 @@
#define MX3_PWMCR_DOZEEN (1 << 24)
#define MX3_PWMCR_WAITEN (1 << 23)
#define MX3_PWMCR_DBGEN (1 << 22)
+#define MX3_PWMCR_POUTC (1 << 18)
#define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16)
#define MX3_PWMCR_CLKSRC_IPG (1 << 16)
#define MX3_PWMCR_SWR (1 << 3)
@@ -180,6 +181,9 @@ static int imx_pwm_config_v2(struct pwm_chip *chip,
if (enable)
cr |= MX3_PWMCR_EN;
+ if (pwm->args.polarity == PWM_POLARITY_INVERSED)
+ cr |= MX3_PWMCR_POUTC;
+
writel(cr, imx->mmio_base + MX3_PWMCR);
return 0;
@@ -240,27 +244,62 @@ static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
clk_disable_unprepare(imx->clk_per);
}
-static struct pwm_ops imx_pwm_ops = {
+static int imx_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+ enum pwm_polarity polarity)
+{
+ struct imx_chip *imx = to_imx_chip(chip);
+ u32 val;
+
+ if (polarity == pwm->args.polarity)
+ return 0;
+
+ val = readl(imx->mmio_base + MX3_PWMCR);
+
+ if (polarity == PWM_POLARITY_INVERSED)
+ val |= MX3_PWMCR_POUTC;
+ else
+ val &= ~MX3_PWMCR_POUTC;
+
+ writel(val, imx->mmio_base + MX3_PWMCR);
+
+ dev_dbg(imx->chip.dev, "%s: polarity set to %s\n", __func__,
+ polarity == PWM_POLARITY_INVERSED ? "inverted" : "normal");
+
+ return 0;
+}
+
+static struct pwm_ops imx_pwm_ops_v1 = {
.enable = imx_pwm_enable,
.disable = imx_pwm_disable,
.config = imx_pwm_config,
.owner = THIS_MODULE,
};
+static struct pwm_ops imx_pwm_ops_v2 = {
+ .enable = imx_pwm_enable,
+ .disable = imx_pwm_disable,
+ .set_polarity = imx_pwm_set_polarity,
+ .config = imx_pwm_config,
+ .owner = THIS_MODULE,
+};
+
struct imx_pwm_data {
int (*config)(struct pwm_chip *chip,
struct pwm_device *pwm, int duty_ns, int period_ns);
void (*set_enable)(struct pwm_chip *chip, bool enable);
+ struct pwm_ops *pwm_ops;
};
static struct imx_pwm_data imx_pwm_data_v1 = {
.config = imx_pwm_config_v1,
.set_enable = imx_pwm_set_enable_v1,
+ .pwm_ops = &imx_pwm_ops_v1,
};
static struct imx_pwm_data imx_pwm_data_v2 = {
.config = imx_pwm_config_v2,
.set_enable = imx_pwm_set_enable_v2,
+ .pwm_ops = &imx_pwm_ops_v2,
};
static const struct of_device_id imx_pwm_dt_ids[] = {
@@ -282,6 +321,8 @@ static int imx_pwm_probe(struct platform_device *pdev)
if (!of_id)
return -ENODEV;
+ data = of_id->data;
+
imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
if (imx == NULL)
return -ENOMEM;
@@ -300,18 +341,22 @@ static int imx_pwm_probe(struct platform_device *pdev)
return PTR_ERR(imx->clk_ipg);
}
- imx->chip.ops = &imx_pwm_ops;
+ imx->chip.ops = data->pwm_ops;
imx->chip.dev = &pdev->dev;
imx->chip.base = -1;
imx->chip.npwm = 1;
imx->chip.can_sleep = true;
+ if (data->pwm_ops->set_polarity) {
+ dev_dbg(&pdev->dev, "PWM supports output inversion\n");
+ imx->chip.of_xlate = of_pwm_xlate_with_flags;
+ imx->chip.of_pwm_n_cells = 3;
+ }
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(imx->mmio_base))
return PTR_ERR(imx->mmio_base);
- data = of_id->data;
imx->config = data->config;
imx->set_enable = data->set_enable;
--
2.9.2
^ permalink raw reply related
* [PATCH v2 2/6] pwm: core: make the PWM_POLARITY flag in DTB optional
From: Bhuvanchandra DV @ 2016-10-01 10:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161001101235.24598-1-bhuvanchandra.dv@toradex.com>
From: Lothar Wassmann <LW@KARO-electronics.de>
Change the pwm chip driver registration, so that a chip driver that supports
polarity inversion can still be used with DTBs that don't provide the
'PWM_POLARITY' flag.
This is done to provide polarity inversion support for the pwm-imx driver
without having to modify all existing DTS files.
Signed-off-by: Lothar Wassmann <LW@KARO-electronics.de>
Signed-off-by: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com>
Suggested-by: Thierry Reding <thierry.reding@gmail.com>
---
drivers/pwm/core.c | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 195373e..aae8db3 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -137,9 +137,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
{
struct pwm_device *pwm;
+ /* check, whether the driver supports a third cell for flags */
if (pc->of_pwm_n_cells < 3)
return ERR_PTR(-EINVAL);
+ /* flags in the third cell are optional */
+ if (args->args_count < 2)
+ return ERR_PTR(-EINVAL);
+
if (args->args[0] >= pc->npwm)
return ERR_PTR(-EINVAL);
@@ -149,10 +154,12 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
pwm->args.period = args->args[1];
- if (args->args[2] & PWM_POLARITY_INVERTED)
- pwm->args.polarity = PWM_POLARITY_INVERSED;
- else
- pwm->args.polarity = PWM_POLARITY_NORMAL;
+ if (args->args_count > 2) {
+ if (args->args[2] & PWM_POLARITY_INVERTED)
+ pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
+ else
+ pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
+ }
return pwm;
}
@@ -163,9 +170,14 @@ of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
{
struct pwm_device *pwm;
+ /* sanity check driver support */
if (pc->of_pwm_n_cells < 2)
return ERR_PTR(-EINVAL);
+ /* all cells are required */
+ if (args->args_count != pc->of_pwm_n_cells)
+ return ERR_PTR(-EINVAL);
+
if (args->args[0] >= pc->npwm)
return ERR_PTR(-EINVAL);
@@ -672,13 +684,6 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
goto put;
}
- if (args.args_count != pc->of_pwm_n_cells) {
- pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name,
- args.np->full_name);
- pwm = ERR_PTR(-EINVAL);
- goto put;
- }
-
pwm = pc->of_xlate(pc, &args);
if (IS_ERR(pwm))
goto put;
--
2.9.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox