* [PATCH 02/14] arm64: Call ARCH_WORKAROUND_2 on transitions between EL0 and EL1
From: Julien Grall @ 2018-05-23 9:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180522150648.28297-3-marc.zyngier@arm.com>
Hi Marc,
On 05/22/2018 04:06 PM, Marc Zyngier wrote:
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index ec2ee720e33e..f33e6aed3037 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
> @@ -18,6 +18,7 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> +#include <linux/arm-smccc.h>
> #include <linux/init.h>
> #include <linux/linkage.h>
>
> @@ -137,6 +138,18 @@ alternative_else_nop_endif
> add \dst, \dst, #(\sym - .entry.tramp.text)
> .endm
>
> + // This macro corrupts x0-x3. It is the caller's duty
> + // to save/restore them if required.
NIT: Shouldn't you use /* ... */ for multi-line comments?
Regardless that:
Reviewed-by: Julien Grall <julien.grall@arm.com>
Cheers,
--
Julien Grall
^ permalink raw reply
* [PATCH 2/2] arm64: dts: renesas: v3hsk: add GEther support
From: Simon Horman @ 2018-05-23 9:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180522085220.vzffiwiwzixlvpkz@verge.net.au>
On Tue, May 22, 2018 at 10:52:21AM +0200, Simon Horman wrote:
> On Fri, May 18, 2018 at 10:46:19PM +0300, Sergei Shtylyov wrote:
> > Define the V3H Starter Kit board dependent part of the GEther device node.
> >
> > Based on the original (and large) patch by Vladimir Barinov.
> >
> > Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
> > Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>
> This looks fine but I will wait to see if there are other reviews before
> applying.
>
> Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
Applied.
^ permalink raw reply
* [PATCH 1/2] arm64: dts: renesas: r8a77980: add GEther support
From: Simon Horman @ 2018-05-23 9:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <9f2c6e9b-a6a9-97f1-7899-3635230acd6f@cogentembedded.com>
On Wed, May 23, 2018 at 12:05:30PM +0300, Sergei Shtylyov wrote:
> Hello!
>
> On 5/23/2018 11:41 AM, Simon Horman wrote:
>
> > > > > Define the generic R8A77980 part of the GEther device node.
> > > > >
> > > > > Based on the original (and large) patch by Vladimir Barinov.
> > > > >
> > > > > Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
> > > > > Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> > > >
> > > > Thanks for your patch!
> > > >
> > > > With the below addressed:
> > > > Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> > >
> > > Thanks!
> > >
> > > > > --- renesas.orig/arch/arm64/boot/dts/renesas/r8a77980.dtsi
> > > > > +++ renesas/arch/arm64/boot/dts/renesas/r8a77980.dtsi
> > > > > @@ -417,6 +417,17 @@
> > > > > dma-channels = <16>;
> > > > > };
> > > > >
> > > > > + gether: ethernet at e7400000 {
> > > > > + compatible = "renesas,gether-r8a77980";
> > > > > + reg = <0 0xe7400000 0 0x1000>;
> > > > > + interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
> > > > > + clocks = <&cpg CPG_MOD 813>;
> > > > > + power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
> > > >
> > > > resets = <&cpg 813>;
> > >
> > > As usual...
> > >
> > > >
> > > > > + #address-cells = <1>;
> > > > > + #size-cells = <0>;
> > > > > + status = "disabled";
> > > >
> > > > Any default phy-mode needed?
> > >
> > > A default "phy-mode" IMO make sense when the MAC supports a single
> > > PHY interface mode. In this case, both RMII and RGMII are supported, so
> > > I coulsn't choose a default...
> >
> > I would think making an arbitrary choice is better than no choice.
> > How does the driver behave in the absence of a default?
>
> The board DT *must* assign some "phy-mode" -- it's a required prop.
> In this particular case, iff the mode is still unspecified, the driver
> will select the MII mode for the RMII_MII reg (which is a reserved value for
> this GEther)...
Thanks, if its required that boards provide this property then
this makes sense to me.
I have applied the patch after adding the resets property.
The result is as follows:
From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Subject: [PATCH] arm64: dts: renesas: r8a77980: add GEther support
Define the generic R8A77980 part of the GEther device node.
Based on the original (and large) patch by Vladimir Barinov.
Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
[simon: add resets property]
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
arch/arm64/boot/dts/renesas/r8a77980.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi
index 6d2b61d83caf..c797db59ae18 100644
--- a/arch/arm64/boot/dts/renesas/r8a77980.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi
@@ -417,6 +417,18 @@
dma-channels = <16>;
};
+ gether: ethernet at e7400000 {
+ compatible = "renesas,gether-r8a77980";
+ reg = <0 0xe7400000 0 0x1000>;
+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 813>;
+ power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
+ resets = <&cpg 813>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
mmc0: mmc at ee140000 {
compatible = "renesas,sdhi-r8a77980",
"renesas,rcar-gen3-sdhi";
--
2.11.0
^ permalink raw reply related
* [PATCH v3] arm64: signal: Report signal frame size to userspace via auxv
From: Dave Martin @ 2018-05-23 9:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180522171916.GL26955@arm.com>
On Tue, May 22, 2018 at 06:19:16PM +0100, Will Deacon wrote:
> Hi Dave,
>
> On Thu, May 17, 2018 at 04:45:41PM +0100, Dave Martin wrote:
> > Stateful CPU architecture extensions may require the signal frame
> > to grow to a size that exceeds the arch's MINSIGSTKSZ #define.
> > However, changing this #define is an ABI break.
>
> [...]
>
> > For arm64 SVE:
> >
> > The SVE context block in the signal frame needs to be considered
> > too when computing the maximum possible signal frame size.
> >
> > Because the size of this block depends on the vector length, this
> > patch computes the size based not on the thread's current vector
> > length but instead on the maximum possible vector length: this
> > determines the maximum size of SVE context block that can be
> > observed in any signal frame for the lifetime of the process.
> >
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Cc: Catalin Marinas <catalin.marinas@arm.com>
> > Cc: Will Deacon <will.deacon@arm.com>
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Cc: Alex Benn?e <alex.bennee@linaro.org>
> >
> > ---
> >
> > Changes since v2:
> >
> > * Redefine AT_MINSIGSTKSZ as 51 to avoid clash with values defined by
> > other architectures.
> >
> > This turns out to be a problem for glibc; also random userspace
> > software does not necessary check the architecture before using
> > getauxval() or otherwise parsing the aux vector, which can make
> > aliased tags problematic.
> >
> > Really, the headers need cleaning up tree-wide in such away that the
> > AT_* definitions do not appear to be arch-private. To be addressed
> > separately.
> > ---
> > arch/arm64/include/asm/elf.h | 11 ++++++++
> > arch/arm64/include/asm/processor.h | 5 ++++
> > arch/arm64/include/uapi/asm/auxvec.h | 3 ++-
> > arch/arm64/kernel/cpufeature.c | 1 +
> > arch/arm64/kernel/signal.c | 51 +++++++++++++++++++++++++++++++-----
> > 5 files changed, 63 insertions(+), 8 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
> > index fac1c4d..dc32adb 100644
> > --- a/arch/arm64/include/asm/elf.h
> > +++ b/arch/arm64/include/asm/elf.h
> > @@ -24,6 +24,11 @@
> > #include <asm/ptrace.h>
> > #include <asm/user.h>
> >
> > +#ifndef __ASSEMBLY__
> > +#include <linux/bug.h>
> > +#include <asm/processor.h> /* for signal_minsigstksz, used by ARCH_DLINFO */
> > +#endif
>
> Maybe move these inside the pre-existing #ifndef __ASSEMBLY__ block.
Mark make the same point. Can do.
> > /*
> > * AArch64 static relocation types.
> > */
> > @@ -146,8 +151,14 @@ typedef struct user_fpsimd_state elf_fpregset_t;
> > /* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
> > #define ARCH_DLINFO \
> > do { \
> > + int minsigstksz = signal_minsigstksz; \
> > + \
> > + if (WARN_ON(minsigstksz <= 0)) \
> > + minsigstksz = MINSIGSTKSZ; \
> > + \
>
> How can this happen?
It can't. minsigstksz == 0 means that it was not initialised yet.
This is a sanity-check for something that is currently guaranteed
by the way the code is structured.
See the related comment on minsigstksz_setup().
Perhaps this should be a WARN_ON_ONCE(), with omission of the
record.
Looking at it again, I don't think we need a WARN both here and in
minsigstksz_setup(). If minsigstksz_setup() goes wrong, we could
leave signal_minsigstksz as 0 and then we'd the WARN here anyway.
>
> > NEW_AUX_ENT(AT_SYSINFO_EHDR, \
> > (elf_addr_t)current->mm->context.vdso); \
> > + NEW_AUX_ENT(AT_MINSIGSTKSZ, minsigstksz); \
> > } while (0)
> >
> > #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
> > diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
> > index 7675989..6f60e92 100644
> > --- a/arch/arm64/include/asm/processor.h
> > +++ b/arch/arm64/include/asm/processor.h
> > @@ -35,6 +35,8 @@
> > #ifdef __KERNEL__
> >
> > #include <linux/build_bug.h>
> > +#include <linux/cache.h>
> > +#include <linux/init.h>
> > #include <linux/stddef.h>
> > #include <linux/string.h>
> >
> > @@ -244,6 +246,9 @@ void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused);
> > void cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused);
> > void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused);
> >
> > +extern int __ro_after_init signal_minsigstksz; /* user signal frame size */
>
> Probably better as unsigned long, to be consistent with the size field
> of the sigframe user layout structure.
Yes, that probably makes sense.
I think the "int" dates back to when I had a prctl() call for returning
this to userspace, since int is the libc return type for prctl.
auxv entries are effectively unsigned long / uint64_t / whatever you
like to call it, so unsigned long would make sense here now.
>
> > +extern void __init minsigstksz_setup(void);
> > +
> > /* Userspace interface for PR_SVE_{SET,GET}_VL prctl()s: */
> > #define SVE_SET_VL(arg) sve_set_current_vl(arg)
> > #define SVE_GET_VL() sve_get_current_vl()
> > diff --git a/arch/arm64/include/uapi/asm/auxvec.h b/arch/arm64/include/uapi/asm/auxvec.h
> > index ec0a86d..743c0b8 100644
> > --- a/arch/arm64/include/uapi/asm/auxvec.h
> > +++ b/arch/arm64/include/uapi/asm/auxvec.h
> > @@ -19,7 +19,8 @@
> >
> > /* vDSO location */
> > #define AT_SYSINFO_EHDR 33
> > +#define AT_MINSIGSTKSZ 51 /* stack needed for signal delivery */
> >
> > -#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
> > +#define AT_VECTOR_SIZE_ARCH 2 /* entries in ARCH_DLINFO */
> >
> > #endif
> > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> > index 9d1b06d..0e0b53d 100644
> > --- a/arch/arm64/kernel/cpufeature.c
> > +++ b/arch/arm64/kernel/cpufeature.c
> > @@ -1619,6 +1619,7 @@ void __init setup_cpu_features(void)
> > pr_info("emulated: Privileged Access Never (PAN) using TTBR0_EL1 switching\n");
> >
> > sve_setup();
> > + minsigstksz_setup();
> >
> > /* Advertise that we have computed the system capabilities */
> > set_sys_caps_initialised();
> > diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
> > index 154b7d3..ae8d4ea 100644
> > --- a/arch/arm64/kernel/signal.c
> > +++ b/arch/arm64/kernel/signal.c
> > @@ -17,6 +17,7 @@
> > * along with this program. If not, see <http://www.gnu.org/licenses/>.
> > */
> >
> > +#include <linux/cache.h>
> > #include <linux/compat.h>
> > #include <linux/errno.h>
> > #include <linux/kernel.h>
> > @@ -570,8 +571,15 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
> > return 0;
> > }
> >
> > -/* Determine the layout of optional records in the signal frame */
> > -static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
> > +/*
> > + * Determine the layout of optional records in the signal frame
> > + *
> > + * add_all: if true, lays out the biggest possible signal frame for
> > + * this task; otherwise, generates a layout for the current state
> > + * of the task.
> > + */
> > +static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
> > + bool add_all)
> > {
> > int err;
> >
> > @@ -581,7 +589,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
> > return err;
> >
> > /* fault information, if valid */
> > - if (current->thread.fault_code) {
> > + if (add_all || current->thread.fault_code) {
> > err = sigframe_alloc(user, &user->esr_offset,
> > sizeof(struct esr_context));
> > if (err)
> > @@ -591,8 +599,18 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
> > if (system_supports_sve()) {
> > unsigned int vq = 0;
> >
> > - if (test_thread_flag(TIF_SVE))
> > - vq = sve_vq_from_vl(current->thread.sve_vl);
> > + if (add_all || test_thread_flag(TIF_SVE)) {
> > + int vl = sve_max_vl;
> > +
> > + if (!add_all)
> > + vl = current->thread.sve_vl;
> > +
> > + /* Fail safe if something wasn't initialised */
> > + if (WARN_ON(!sve_vl_valid(vl)))
> > + vl = SVE_VL_MIN;
>
> How can this happen?
It can't. It is a sanity-check that things were set up in the right
order. To fall foul of this, the cpufeatures setup would need not to
have been completed yet.
For now, this is impossible by construction, because this should only
be called for user tasks, or from the end of cpufeatures setup via
minsigstksz_setup().
This WARN_ON() is a defence against future refactoring breaking these
assumptions. I can elaborate the comment if you like, but I think it's
a good idea to keep some kind of check.
>
> > +
> > + vq = sve_vq_from_vl(vl);
> > + }
> >
> > err = sigframe_alloc(user, &user->sve_offset,
> > SVE_SIG_CONTEXT_SIZE(vq));
> > @@ -603,7 +621,6 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
> > return sigframe_alloc_end(user);
> > }
> >
> > -
> > static int setup_sigframe(struct rt_sigframe_user_layout *user,
> > struct pt_regs *regs, sigset_t *set)
> > {
> > @@ -701,7 +718,7 @@ static int get_sigframe(struct rt_sigframe_user_layout *user,
> > int err;
> >
> > init_user_layout(user);
> > - err = setup_sigframe_layout(user);
> > + err = setup_sigframe_layout(user, false);
> > if (err)
> > return err;
> >
> > @@ -936,3 +953,23 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
> > thread_flags = READ_ONCE(current_thread_info()->flags);
> > } while (thread_flags & _TIF_WORK_MASK);
> > }
> > +
> > +int __ro_after_init signal_minsigstksz;
> > +
> > +/*
> > + * Determine the stack space required for guaranteed signal devliery.
> > + * This function is used to populate AT_MINSIGSTKSZ at process startup.
> > + */
> > +void __init minsigstksz_setup(void)
> > +{
> > + struct rt_sigframe_user_layout user;
> > +
> > + init_user_layout(&user);
> > +
> > + if (WARN_ON(setup_sigframe_layout(&user, true)))
> > + signal_minsigstksz = SIGSTKSZ;
>
> Why not just omit the aux record in this case? Something has gone badly
> wrong, so it's unlikely we're going to get much further anyway.
It wasn't clear to me whether arch auxv entries can be optional. But it
looks like binfmt_elf.c:create_elf_table() fills any unused tail of the
aux vector for AT_NULL, which should fix that.
Since my recommendation would be to assume MINSIGSTKSZ if the entry
isn't there, omitting makes sense if we don't have a better guess.
Cheers
---Dave
^ permalink raw reply
* [PATCH 8/9] PM / Domains: Add support for multi PM domains per device to genpd
From: Jon Hunter @ 2018-05-23 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAPDyKFo_69kSS6UzdsJeyeiiED=S=chsdkP+R43qMHDEbZ8n_A@mail.gmail.com>
On 23/05/18 07:12, Ulf Hansson wrote:
...
>>>>> Thanks for sending this. Believe it or not this has still been on my to-do list
>>>>> and so we definitely need a solution for Tegra.
>>>>>
>>>>> Looking at the above it appears that additional power-domains exposed as devices
>>>>> to the client device. So I assume that this means that the drivers for devices
>>>>> with multiple power-domains will need to call RPM APIs for each of these
>>>>> additional power-domains. Is that correct?
>>>>
>>>> They can, but should not!
>>>>
>>>> Instead, the driver shall use device_link_add() and device_link_del(),
>>>> dynamically, depending on what PM domain that their original device
>>>> needs for the current running use case.
>>>>
>>>> In that way, they keep existing runtime PM deployment, operating on
>>>> its original device.
>>>
>>> OK, sounds good. Any reason why the linking cannot be handled by the above API? Is there a use-case where you would not want it linked?
>>
>> I am guessing the linking is what would give the driver the ability to decide which subset of powerdomains it actually wants to control
>> at any point using runtime PM. If we have cases wherein the driver would want to turn on/off _all_ its associated powerdomains _always_
>> then a default linking of all would help.
>
> First, I think we need to decide on *where* the linking should be
> done, not at both places, as that would just mess up synchronization
> of who is responsible for calling the device_link_del() at detach.
>
> Second, It would in principle be fine to call device_link_add() and
> device_link_del() as a part of the attach/detach APIs. However, there
> is a downside to such solution, which would be that the driver then
> needs call the detach API, just to do device_link_del(). Of course
> then it would also needs to call the attach API later if/when needed.
> Doing this adds unnecessary overhead - comparing to just let the
> driver call device_link_add|del() when needed. On the upside, yes, it
> would put less burden on the drivers as it then only needs to care
> about using one set of functions.
>
> Which solution do you prefer?
Any reason why we could not add a 'boolean' argument to the API to
indicate whether the new device should be linked? I think that I prefer
the API handles it, but I can see there could be instances where drivers
may wish to handle it themselves.
Rajendra, do you have a use-case right now where the driver would want
to handle the linking?
Cheers
Jon
--
nvpublic
^ permalink raw reply
* [PATCH v3 3/3] ARM: dts: imx6ull-colibri-wifi: remove operating points
From: Stefan Agner @ 2018-05-23 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180523043032.2htohlypynnvpiye@vireshk-i7>
On 23.05.2018 06:30, Viresh Kumar wrote:
> On 22-05-18, 08:28, S?bastien Szymanski wrote:
>> Operating points are now defined in the imx6ull.dtsi file so remove
>> them from board device trees.
>>
>> Signed-off-by: S?bastien Szymanski <sebastien.szymanski@armadeus.com>
>> ---
>> arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi | 14 --------------
>> 1 file changed, 14 deletions(-)
>>
>> diff --git a/arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi b/arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi
>> index 3dffbcd50bf6..183193e8580d 100644
>> --- a/arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi
>> +++ b/arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi
>> @@ -20,20 +20,6 @@
>>
>> &cpu0 {
>> clock-frequency = <792000000>;
>> - operating-points = <
>> - /* kHz uV */
>> - 792000 1225000
>> - 528000 1175000
>> - 396000 1025000
>> - 198000 950000
>> - >;
>> - fsl,soc-operating-points = <
>> - /* KHz uV */
>> - 792000 1175000
>> - 528000 1175000
>> - 396000 1175000
>> - 198000 1175000
>> - >;
>> };
>>
>> &iomuxc {
>
> Maybe you should merge this with the previous patch itself.
I am with Viresh here, I rather prefer this in a single commit so it is
clear that frequencies moved to the base device tree.
Also, add a comment that frequency selection is now handled in code,
e.g.:
"The valid frequencies for a particular SKU are now selected by the
cpufreq driver according to ratings stored in OTP fuses."
But the two device tree changes with the driver do what they should do
here, so:
Tested-by: Stefan Agner <stefan@agner.ch>
Reviewed-by: Stefan Agner <stefan@agner.ch>
--
Stefan
^ permalink raw reply
* [PATCH] arm64: alternative:flush cache with unpatched code
From: Will Deacon @ 2018-05-23 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527012451-16117-1-git-send-email-rokhanna@nvidia.com>
Hi Rohit,
On Tue, May 22, 2018 at 11:07:31AM -0700, Rohit Khanna wrote:
> In the current implementation, __apply_alternatives patches
> flush_icache_range and then executes it without invalidating the icache.
> Thus, icache can contain some of the old instructions for
> flush_icache_range. This can cause unpredictable behavior as during
> execution we can get a mix of old and new instructions for
> flush_icache_range.
>
> This patch :
>
> 1. Adds a new function flush_cache_kernel_range for flushing kernel
> memory range. This function is not patched during boot and can be safely
> used to flush cache during code patching.
>
> 2. Modifies __apply_alternatives so that it uses
> flush_cache_kernel_range to flush the cache range after patching code.
>
> Signed-off-by: Rohit Khanna <rokhanna@nvidia.com>
> ---
> arch/arm64/include/asm/cacheflush.h | 1 +
> arch/arm64/kernel/alternative.c | 2 +-
> arch/arm64/mm/cache.S | 42 +++++++++++++++++++++++++++++++++++++
> 3 files changed, 44 insertions(+), 1 deletion(-)
Thanks for the patch; this is a horrible bug :)
Comments below.
> diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
> index 30334d81b021..1366f00297c3 100644
> --- a/arch/arm64/mm/cache.S
> +++ b/arch/arm64/mm/cache.S
> @@ -81,6 +81,48 @@ ENDPROC(flush_icache_range)
> ENDPROC(__flush_cache_user_range)
>
> /*
> + * flush_cache_kernel_range(start,end)
> + *
> + * Ensure that the I and D caches are coherent within specified kernel
> + * region.
> + * This is typically used when code has been written to a kernel memory
> + * region and will be executed.
> + *
> + * NOTE - This macro cannot have "alternatives" applied to it as its
> + * used to update alternatives
> + *
> + * - start - virtual start address of region
> + * - end - virtual end address of region
> + */
> +ENTRY(flush_cache_kernel_range)
> + raw_dcache_line_size x2, x3
> + sub x3, x2, #1
> + bic x4, x0, x3
> +1:
> + dc civac, x4 /* Use civac instead of cvau. This is required
> + * due to ARM errata 826319, 827319, 824069,
> + * 819472 on A53
> + */
> + add x4, x4, x2
> + cmp x4, x1
> + b.lo 1b
> + dsb ish
> +
> + raw_icache_line_size x2, x3
Won't this be broken on systems that misreport the line size in CTR?
> + sub x3, x2, #1
> + bic x4, x0, x3
> +1:
> + ic ivau, x4 // invalidate I line PoU
> + add x4, x4, x2
> + cmp x4, x1
> + b.lo 1b
> + dsb ish
> + isb
> + mov x0, #0
> + ret
> +ENDPROC(flush_cache_kernel_range)
Generally, I don't think we want to expose this function as it's not going
to be the right thing to call outside of the alternatives patching. Instead,
can we:
1. Code this up in alternative.c, mostly in C code and always using the
sanitised feature register value for the CTR
2. Just call __flush_icache_all once after patching is complete (and
add a comment to __flush_icache_all saying that it's used by the
patching code)
That way, we're keeping the implementation private and simple so we can
hopefully avoid running into this problem again.
Cheers,
Will
^ permalink raw reply
* [PATCH 1/2] arm64: dts: renesas: r8a77980: add GEther support
From: Sergei Shtylyov @ 2018-05-23 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180523084100.ynv3zoqrikcxem5f@verge.net.au>
Hello!
On 5/23/2018 11:41 AM, Simon Horman wrote:
>>>> Define the generic R8A77980 part of the GEther device node.
>>>>
>>>> Based on the original (and large) patch by Vladimir Barinov.
>>>>
>>>> Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
>>>> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>>>
>>> Thanks for your patch!
>>>
>>> With the below addressed:
>>> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
>>
>> Thanks!
>>
>>>> --- renesas.orig/arch/arm64/boot/dts/renesas/r8a77980.dtsi
>>>> +++ renesas/arch/arm64/boot/dts/renesas/r8a77980.dtsi
>>>> @@ -417,6 +417,17 @@
>>>> dma-channels = <16>;
>>>> };
>>>>
>>>> + gether: ethernet at e7400000 {
>>>> + compatible = "renesas,gether-r8a77980";
>>>> + reg = <0 0xe7400000 0 0x1000>;
>>>> + interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
>>>> + clocks = <&cpg CPG_MOD 813>;
>>>> + power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
>>>
>>> resets = <&cpg 813>;
>>
>> As usual...
>>
>>>
>>>> + #address-cells = <1>;
>>>> + #size-cells = <0>;
>>>> + status = "disabled";
>>>
>>> Any default phy-mode needed?
>>
>> A default "phy-mode" IMO make sense when the MAC supports a single
>> PHY interface mode. In this case, both RMII and RGMII are supported, so
>> I coulsn't choose a default...
>
> I would think making an arbitrary choice is better than no choice.
> How does the driver behave in the absence of a default?
The board DT *must* assign some "phy-mode" -- it's a required prop.
In this particular case, iff the mode is still unspecified, the driver
will select the MII mode for the RMII_MII reg (which is a reserved value for
this GEther)...
[...]
MBR, Sergei
^ permalink raw reply
* [PATCH] cpufreq: Add Kryo CPU scaling driver
From: Ilia Lin @ 2018-05-23 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1526729701-8589-1-git-send-email-ilialin@codeaurora.org>
In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors,
the CPU frequency subset and voltage value of each OPP varies
based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables
defines the voltage and frequency value based on the msm-id in SMEM
and speedbin blown in the efuse combination.
The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC
to provide the OPP framework with required information.
This is used to determine the voltage and frequency value for each OPP of
operating-points-v2 table when it is parsed by the OPP framework.
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
drivers/cpufreq/Kconfig.arm | 10 +++
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/cpufreq-dt-platdev.c | 3 +
drivers/cpufreq/qcom-cpufreq-kryo.c | 163 +++++++++++++++++++++++++++++++++++
4 files changed, 177 insertions(+)
create mode 100644 drivers/cpufreq/qcom-cpufreq-kryo.c
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index de55c7d..0bfd40e 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -124,6 +124,16 @@ config ARM_OMAP2PLUS_CPUFREQ
depends on ARCH_OMAP2PLUS
default ARCH_OMAP2PLUS
+config ARM_QCOM_CPUFREQ_KRYO
+ bool "Qualcomm Kryo based CPUFreq"
+ depends on QCOM_QFPROM
+ depends on QCOM_SMEM
+ select PM_OPP
+ help
+ This adds the CPUFreq driver for Qualcomm Kryo SoC based boards.
+
+ If in doubt, say N.
+
config ARM_S3C_CPUFREQ
bool
help
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 8d24ade..fb4a2ec 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
+obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o
obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 3b585e4..77d6ab8 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -118,6 +118,9 @@
{ .compatible = "nvidia,tegra124", },
+ { .compatible = "qcom,apq8096", },
+ { .compatible = "qcom,msm8996", },
+
{ .compatible = "st,stih407", },
{ .compatible = "st,stih410", },
diff --git a/drivers/cpufreq/qcom-cpufreq-kryo.c b/drivers/cpufreq/qcom-cpufreq-kryo.c
new file mode 100644
index 0000000..885051e
--- /dev/null
+++ b/drivers/cpufreq/qcom-cpufreq-kryo.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/*
+ * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors,
+ * the CPU frequency subset and voltage value of each OPP varies
+ * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables
+ * defines the voltage and frequency value based on the msm-id in SMEM
+ * and speedbin blown in the efuse combination.
+ * The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC
+ * to provide the OPP framework with required information.
+ * This is used to determine the voltage and frequency value for each OPP of
+ * operating-points-v2 table when it is parsed by the OPP framework.
+ */
+
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/smem.h>
+
+#define MSM_ID_SMEM 137
+
+enum _msm_id {
+ MSM8996V3 = 0xF6ul,
+ APQ8096V3 = 0x123ul,
+ MSM8996SG = 0x131ul,
+ APQ8096SG = 0x138ul,
+};
+
+enum _msm8996_version {
+ MSM8996_V3,
+ MSM8996_SG,
+ NUM_OF_MSM8996_VERSIONS,
+};
+
+static enum _msm8996_version __init qcom_cpufreq_kryo_get_msm_id(void)
+{
+ size_t len;
+ u32 *msm_id;
+ enum _msm8996_version version;
+
+ msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len);
+ /* The first 4 bytes are format, next to them is the actual msm-id */
+ msm_id++;
+
+ switch ((enum _msm_id)*msm_id) {
+ case MSM8996V3:
+ case APQ8096V3:
+ version = MSM8996_V3;
+ break;
+ case MSM8996SG:
+ case APQ8096SG:
+ version = MSM8996_SG;
+ break;
+ default:
+ version = NUM_OF_MSM8996_VERSIONS;
+ }
+
+ return version;
+}
+
+static int __init qcom_cpufreq_kryo_driver_init(void)
+{
+ struct opp_table *opp_tables[NR_CPUS] = {0};
+ enum _msm8996_version msm8996_version;
+ struct nvmem_cell *speedbin_nvmem;
+ struct platform_device *pdev;
+ struct device_node *np;
+ struct device *cpu_dev;
+ unsigned cpu;
+ u8 *speedbin;
+ u32 versions;
+ size_t len;
+ int ret;
+
+ cpu_dev = get_cpu_device(0);
+ if (NULL == cpu_dev)
+ return -ENODEV;
+
+ msm8996_version = qcom_cpufreq_kryo_get_msm_id();
+ if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
+ dev_err(cpu_dev, "Not Snapdragon 820/821!");
+ return -ENODEV;
+ }
+
+ np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
+ if (IS_ERR(np))
+ return PTR_ERR(np);
+
+ if (!of_device_is_compatible(np, "operating-points-v2-kryo-cpu")) {
+ ret = -ENOENT;
+ goto free_np;
+ }
+
+ speedbin_nvmem = of_nvmem_cell_get(np, NULL);
+ if (IS_ERR(speedbin_nvmem)) {
+ ret = PTR_ERR(speedbin_nvmem);
+ dev_err(cpu_dev, "Could not get nvmem cell: %d\n", ret);
+ goto free_np;
+ }
+
+ speedbin = nvmem_cell_read(speedbin_nvmem, &len);
+ nvmem_cell_put(speedbin_nvmem);
+
+ switch (msm8996_version) {
+ case MSM8996_V3:
+ versions = 1 << (unsigned int)(*speedbin);
+ break;
+ case MSM8996_SG:
+ versions = 1 << ((unsigned int)(*speedbin) + 4);
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ for_each_possible_cpu(cpu) {
+ cpu_dev = get_cpu_device(cpu);
+ if (NULL == cpu_dev) {
+ ret = -ENODEV;
+ goto free_opp;
+ }
+
+ opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev,
+ &versions, 1);
+ if (IS_ERR(opp_tables[cpu])) {
+ ret = PTR_ERR(opp_tables[cpu]);
+ dev_err(cpu_dev, "Failed to set supported hardware\n");
+ goto free_opp;
+ }
+ }
+
+ pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+ if (!IS_ERR(pdev))
+ return 0;
+
+ ret = PTR_ERR(pdev);
+ dev_err(cpu_dev, "Failed to register platform device\n");
+
+free_opp:
+ for_each_possible_cpu(cpu) {
+ if (IS_ERR_OR_NULL(opp_tables[cpu]))
+ break;
+ dev_pm_opp_put_supported_hw(opp_tables[cpu]);
+ }
+free_np:
+ of_node_put(np);
+
+ return ret;
+}
+late_initcall(qcom_cpufreq_kryo_driver_init);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH v3 1/3] cpufreq: imx6q: check speed grades for i.MX6ULL
From: Stefan Agner @ 2018-05-23 9:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180522062853.24799-1-sebastien.szymanski@armadeus.com>
On 22.05.2018 08:28, S?bastien Szymanski wrote:
> Check the max speed supported from the fuses for i.MX6ULL and update the
> operating points table accordingly.
>
> Signed-off-by: S?bastien Szymanski <sebastien.szymanski@armadeus.com>
Tested with a 528MHz and 792MHz rated i.MX 6ULL, looks good!
Tested-by: Stefan Agner <stefan@agner.ch>
Reviewed-by: Stefan Agner <stefan@agner.ch>
--
Stefan
> ---
>
> Changes for v3:
> - none
>
> Changes for v2:
> - none
>
> drivers/cpufreq/imx6q-cpufreq.c | 29 +++++++++++++++++++++++------
> 1 file changed, 23 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
> index 83cf631fc9bc..f094687cae52 100644
> --- a/drivers/cpufreq/imx6q-cpufreq.c
> +++ b/drivers/cpufreq/imx6q-cpufreq.c
> @@ -266,6 +266,8 @@ static void imx6q_opp_check_speed_grading(struct
> device *dev)
> }
>
> #define OCOTP_CFG3_6UL_SPEED_696MHZ 0x2
> +#define OCOTP_CFG3_6ULL_SPEED_792MHZ 0x2
> +#define OCOTP_CFG3_6ULL_SPEED_900MHZ 0x3
>
> static void imx6ul_opp_check_speed_grading(struct device *dev)
> {
> @@ -287,16 +289,30 @@ static void
> imx6ul_opp_check_speed_grading(struct device *dev)
> * Speed GRADING[1:0] defines the max speed of ARM:
> * 2b'00: Reserved;
> * 2b'01: 528000000Hz;
> - * 2b'10: 696000000Hz;
> - * 2b'11: Reserved;
> + * 2b'10: 696000000Hz on i.MX6UL, 792000000Hz on i.MX6ULL;
> + * 2b'11: 900000000Hz on i.MX6ULL only;
> * We need to set the max speed of ARM according to fuse map.
> */
> val = readl_relaxed(base + OCOTP_CFG3);
> val >>= OCOTP_CFG3_SPEED_SHIFT;
> val &= 0x3;
> - if (val != OCOTP_CFG3_6UL_SPEED_696MHZ)
> - if (dev_pm_opp_disable(dev, 696000000))
> - dev_warn(dev, "failed to disable 696MHz OPP\n");
> +
> + if (of_machine_is_compatible("fsl,imx6ul")) {
> + if (val != OCOTP_CFG3_6UL_SPEED_696MHZ)
> + if (dev_pm_opp_disable(dev, 696000000))
> + dev_warn(dev, "failed to disable 696MHz OPP\n");
> + }
> +
> + if (of_machine_is_compatible("fsl,imx6ull")) {
> + if (val != OCOTP_CFG3_6ULL_SPEED_792MHZ)
> + if (dev_pm_opp_disable(dev, 792000000))
> + dev_warn(dev, "failed to disable 792MHz OPP\n");
> +
> + if (val != OCOTP_CFG3_6ULL_SPEED_900MHZ)
> + if (dev_pm_opp_disable(dev, 900000000))
> + dev_warn(dev, "failed to disable 900MHz OPP\n");
> + }
> +
> iounmap(base);
> put_node:
> of_node_put(np);
> @@ -356,7 +372,8 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
> goto put_reg;
> }
>
> - if (of_machine_is_compatible("fsl,imx6ul"))
> + if (of_machine_is_compatible("fsl,imx6ul") ||
> + of_machine_is_compatible("fsl,imx6ull"))
> imx6ul_opp_check_speed_grading(cpu_dev);
> else
> imx6q_opp_check_speed_grading(cpu_dev);
^ permalink raw reply
* [rjarzmik:test/daniel 23/34] sound/arm/pxa2xx-ac97.c:27:10: fatal error: mach/regs-ac97.h: No such file or directory
From: Daniel Mack @ 2018-05-23 9:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201805231623.n3Qx9qdU%fengguang.wu@intel.com>
Robert,
On Wednesday, May 23, 2018 10:46 AM, kbuild test robot wrote:
> tree: https://github.com/rjarzmik/linux test/daniel
> head: f495e2dbc482d8f01a1ee20e86284ee9c0c8fa98
> commit: 4cd654b13b9bcc0f206d414497b798ed42df573a [23/34] HACK: select SND_PXA_SOC_SSP for SND_SIMPLE_CARD
This patch is just a local hack in one of my scratch-pad branches and is
not meant for upstream inclusion. Could you remove the branch or make
sure it isn't picked up by test robots?
Thanks,
Daniel
> config: x86_64-randconfig-s3-05231547 (attached as .config)
> compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
> reproduce:
> git checkout 4cd654b13b9bcc0f206d414497b798ed42df573a
> # save the attached .config to linux build tree
> make ARCH=x86_64
>
> All errors (new ones prefixed by >>):
>
>>> sound/arm/pxa2xx-ac97.c:27:10: fatal error: mach/regs-ac97.h: No such file or directory
> #include <mach/regs-ac97.h>
> ^~~~~~~~~~~~~~~~~~
> compilation terminated.
> --
>>> sound/soc/pxa/pxa2xx-i2s.c:28:10: fatal error: mach/hardware.h: No such file or directory
> #include <mach/hardware.h>
> ^~~~~~~~~~~~~~~~~
> compilation terminated.
>
> vim +27 sound/arm/pxa2xx-ac97.c
>
> 2c484df0 Takashi Iwai 2005-06-30 26
> 1f017a99 Eric Miao 2008-11-28 @27 #include <mach/regs-ac97.h>
> a09e64fb Russell King 2008-08-05 28 #include <mach/audio.h>
> 2c484df0 Takashi Iwai 2005-06-30 29
>
> :::::: The code at line 27 was first introduced by commit
> :::::: 1f017a9964c5b3b9581d3a5732110cb1e0444281 [ARM] pxa: move AC97 register definitions into dedicated regs-ac97.h
>
> :::::: TO: Eric Miao <eric.miao@marvell.com>
> :::::: CC: Eric Miao <eric.miao@marvell.com>
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation
>
^ permalink raw reply
* [next, PATCH 6/6] usb: mtu3: fix warning of sleep in atomic context in notifier callback
From: Chunfeng Yun @ 2018-05-23 8:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1291b13a362eaa0cccd30cb8dd4f56d33e1d172d.1527065109.git.chunfeng.yun@mediatek.com>
The notifier callbacks of extcon are called in atomic context, but the
callbacks will call regulator_enable()/regulator_disable() which may
sleep caused by mutex, so use work queue to call the sleep functions.
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/usb/mtu3/mtu3.h | 11 ++++++++++-
drivers/usb/mtu3/mtu3_dr.c | 44 ++++++++++++++++++++++++++++++++++++--------
2 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index a56fee0..87823ac 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -196,7 +196,12 @@ struct mtu3_gpd_ring {
* @vbus: vbus 5V used by host mode
* @edev: external connector used to detect vbus and iddig changes
* @vbus_nb: notifier for vbus detection
-* @vbus_nb: notifier for iddig(idpin) detection
+* @vbus_work : work of vbus detection notifier, used to avoid sleep in
+* notifier callback which is atomic context
+* @vbus_event : event of vbus detecion notifier
+* @id_nb : notifier for iddig(idpin) detection
+* @id_work : work of iddig detection notifier
+* @id_event : event of iddig detecion notifier
* @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
* @manual_drd_enabled: it's true when supports dual-role device by debugfs
* to switch host/device modes depending on user input.
@@ -205,7 +210,11 @@ struct otg_switch_mtk {
struct regulator *vbus;
struct extcon_dev *edev;
struct notifier_block vbus_nb;
+ struct work_struct vbus_work;
+ unsigned long vbus_event;
struct notifier_block id_nb;
+ struct work_struct id_work;
+ unsigned long id_event;
bool is_u3_drd;
bool manual_drd_enabled;
};
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index 80083e0..8c3bbf7 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -174,16 +174,40 @@ static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx,
}
}
-static int ssusb_id_notifier(struct notifier_block *nb,
- unsigned long event, void *ptr)
+static void ssusb_id_work(struct work_struct *work)
{
struct otg_switch_mtk *otg_sx =
- container_of(nb, struct otg_switch_mtk, id_nb);
+ container_of(work, struct otg_switch_mtk, id_work);
- if (event)
+ if (otg_sx->id_event)
ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
else
ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
+}
+
+static void ssusb_vbus_work(struct work_struct *work)
+{
+ struct otg_switch_mtk *otg_sx =
+ container_of(work, struct otg_switch_mtk, vbus_work);
+
+ if (otg_sx->vbus_event)
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+ else
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+}
+
+/*
+ * @ssusb_id_notifier is called in atomic context, but @ssusb_set_mailbox
+ * may sleep, so use work queue here
+ */
+static int ssusb_id_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct otg_switch_mtk *otg_sx =
+ container_of(nb, struct otg_switch_mtk, id_nb);
+
+ otg_sx->id_event = event;
+ schedule_work(&otg_sx->id_work);
return NOTIFY_DONE;
}
@@ -194,10 +218,8 @@ static int ssusb_vbus_notifier(struct notifier_block *nb,
struct otg_switch_mtk *otg_sx =
container_of(nb, struct otg_switch_mtk, vbus_nb);
- if (event)
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
- else
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+ otg_sx->vbus_event = event;
+ schedule_work(&otg_sx->vbus_work);
return NOTIFY_DONE;
}
@@ -398,6 +420,9 @@ int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+ INIT_WORK(&otg_sx->id_work, ssusb_id_work);
+ INIT_WORK(&otg_sx->vbus_work, ssusb_vbus_work);
+
if (otg_sx->manual_drd_enabled)
ssusb_debugfs_init(ssusb);
else
@@ -412,4 +437,7 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
if (otg_sx->manual_drd_enabled)
ssusb_debugfs_exit(ssusb);
+
+ cancel_work_sync(&otg_sx->id_work);
+ cancel_work_sync(&otg_sx->vbus_work);
}
--
1.9.1
^ permalink raw reply related
* [next, PATCH 5/6] usb: mtu3: reset gadget when VBUS_FALL interrupt arises
From: Chunfeng Yun @ 2018-05-23 8:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1291b13a362eaa0cccd30cb8dd4f56d33e1d172d.1527065109.git.chunfeng.yun@mediatek.com>
When VBUS_FALL interrupt arises, it means U3 device is disconnected
with host, so need reset status of gadget
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/usb/mtu3/mtu3_core.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index 279f9cd..eecfd06 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -668,8 +668,10 @@ static irqreturn_t mtu3_u3_ltssm_isr(struct mtu3 *mtu)
if (ltssm & (HOT_RST_INTR | WARM_RST_INTR))
mtu3_gadget_reset(mtu);
- if (ltssm & VBUS_FALL_INTR)
+ if (ltssm & VBUS_FALL_INTR) {
mtu3_ss_func_set(mtu, false);
+ mtu3_gadget_reset(mtu);
+ }
if (ltssm & VBUS_RISE_INTR)
mtu3_ss_func_set(mtu, true);
--
1.9.1
^ permalink raw reply related
* [next, PATCH 4/6] usb: mtu3: avoid sleep in atomic context when enter test mode
From: Chunfeng Yun @ 2018-05-23 8:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1291b13a362eaa0cccd30cb8dd4f56d33e1d172d.1527065109.git.chunfeng.yun@mediatek.com>
Use readl_poll_timeout_atomic() instead of readl_poll_timeout()
in atomic context
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/usb/mtu3/mtu3_gadget_ep0.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c
index 0d2b1cf..25216e7 100644
--- a/drivers/usb/mtu3/mtu3_gadget_ep0.c
+++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c
@@ -299,7 +299,7 @@ static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND);
/* wait for ACK status sent by host */
- readl_poll_timeout(mbase + U3D_EP0CSR, value,
+ readl_poll_timeout_atomic(mbase + U3D_EP0CSR, value,
!(value & EP0_DATAEND), 100, 5000);
mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr);
--
1.9.1
^ permalink raw reply related
* [next, PATCH 3/6] usb: mtu3: clear test_mode flag when reset
From: Chunfeng Yun @ 2018-05-23 8:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1291b13a362eaa0cccd30cb8dd4f56d33e1d172d.1527065109.git.chunfeng.yun@mediatek.com>
Clear test_mode flag when the gadget is reset by host, otherwise
will affect the next test item.
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/usb/mtu3/mtu3_gadget.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index de0de01..5c60a8c 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -719,4 +719,5 @@ void mtu3_gadget_reset(struct mtu3 *mtu)
mtu->u1_enable = 0;
mtu->u2_enable = 0;
mtu->delayed_status = false;
+ mtu->test_mode = false;
}
--
1.9.1
^ permalink raw reply related
* [next, PATCH 2/6] usb: mtu3: fix uncontinuous SeqN issue after disable EP
From: Chunfeng Yun @ 2018-05-23 8:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1291b13a362eaa0cccd30cb8dd4f56d33e1d172d.1527065109.git.chunfeng.yun@mediatek.com>
Reset EP when disable it to reset data toggle for U2 EP, and
SeqN, flow control status etc for U3 EP, this can avoid
issue of uncontinuous SeqN
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/usb/mtu3/mtu3_core.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index 65ff53a..279f9cd 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -195,6 +195,16 @@ static void mtu3_intr_enable(struct mtu3 *mtu)
mtu3_writel(mbase, U3D_DEV_LINK_INTR_ENABLE, SSUSB_DEV_SPEED_CHG_INTR);
}
+/* reset: u2 - data toggle, u3 - SeqN, flow control status etc */
+static void mtu3_ep_reset(struct mtu3_ep *mep)
+{
+ struct mtu3 *mtu = mep->mtu;
+ u32 rst_bit = EP_RST(mep->is_in, mep->epnum);
+
+ mtu3_setbits(mtu->mac_base, U3D_EP_RST, rst_bit);
+ mtu3_clrbits(mtu->mac_base, U3D_EP_RST, rst_bit);
+}
+
/* set/clear the stall and toggle bits for non-ep0 */
void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set)
{
@@ -220,8 +230,7 @@ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set)
}
if (!set) {
- mtu3_setbits(mbase, U3D_EP_RST, EP_RST(mep->is_in, epnum));
- mtu3_clrbits(mbase, U3D_EP_RST, EP_RST(mep->is_in, epnum));
+ mtu3_ep_reset(mep);
mep->flags &= ~MTU3_EP_STALL;
} else {
mep->flags |= MTU3_EP_STALL;
@@ -400,6 +409,7 @@ void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep)
mtu3_setbits(mbase, U3D_QIECR0, QMU_RX_DONE_INT(epnum));
}
+ mtu3_ep_reset(mep);
ep_fifo_free(mep);
dev_dbg(mtu->dev, "%s: %s\n", __func__, mep->name);
--
1.9.1
^ permalink raw reply related
* [next, PATCH 1/6] usb: mtu3: re-enable controller to accept LPM request after LPM resume
From: Chunfeng Yun @ 2018-05-23 8:53 UTC (permalink / raw)
To: linux-arm-kernel
After the controller receives a LPM request, it will reject the LPM
request, and need software to re-enable it after LPM resume if the
controller doesn't remote wakeup from L1 automatically
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/usb/mtu3/mtu3_core.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index b1b99a8..65ff53a 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -176,7 +176,7 @@ static void mtu3_intr_enable(struct mtu3 *mtu)
mtu3_writel(mbase, U3D_LV1IESR, value);
/* Enable U2 common USB interrupts */
- value = SUSPEND_INTR | RESUME_INTR | RESET_INTR;
+ value = SUSPEND_INTR | RESUME_INTR | RESET_INTR | LPM_RESUME_INTR;
mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value);
if (mtu->is_u3_ip) {
@@ -692,6 +692,12 @@ static irqreturn_t mtu3_u2_common_isr(struct mtu3 *mtu)
if (u2comm & RESET_INTR)
mtu3_gadget_reset(mtu);
+ if (u2comm & LPM_RESUME_INTR) {
+ if (!(mtu3_readl(mbase, U3D_POWER_MANAGEMENT) & LPM_HRWE))
+ mtu3_setbits(mbase, U3D_USB20_MISC_CONTROL,
+ LPM_U3_ACK_EN);
+ }
+
return IRQ_HANDLED;
}
--
1.9.1
^ permalink raw reply related
* [PATCH v7 5/5] drm/rockchip: support dp training outside dp firmware
From: Enric Balletbo Serra @ 2018-05-23 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527061353-16902-5-git-send-email-hl@rock-chips.com>
2018-05-23 9:42 GMT+02:00 Lin Huang <hl@rock-chips.com>:
> DP firmware uses fixed phy config values to do training, but some
> boards need to adjust these values to fit for their unique hardware
> design. So get phy config values from dts and use software link training
> instead of relying on firmware, if software training fail, keep firmware
> training as a fallback if sw training fails.
>
> Signed-off-by: Chris Zhong <zyw@rock-chips.com>
> Signed-off-by: Lin Huang <hl@rock-chips.com>
> Reviewed-by: Sean Paul <seanpaul@chromium.org>
> ---
> Changes in v2:
> - update patch following Enric suggest
> Changes in v3:
> - use variable fw_training instead sw_training_success
> - base on DP SPCE, if training fail use lower link rate to retry training
> Changes in v4:
> - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest
> Changes in v5:
> - fix some whitespcae issue
> Changes in v6:
> - None
> Changes in v7:
> - None
>
> drivers/gpu/drm/rockchip/Makefile | 3 +-
> drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +-
> drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 +
> drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 ++++++++++++++++++++++++
> drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +-
> drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++-
> 6 files changed, 505 insertions(+), 13 deletions(-)
> create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c
>
> diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
> index a314e21..b932f62 100644
> --- a/drivers/gpu/drm/rockchip/Makefile
> +++ b/drivers/gpu/drm/rockchip/Makefile
> @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
> rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
>
> rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
> -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
> +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \
> + cdn-dp-link-training.o
> rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
> rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
> rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> index cce64c1..783d57a 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
> goto out;
> }
> }
> -
> - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
> - if (ret) {
> - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret);
> - goto out;
> + if (dp->use_fw_training) {
> + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
> + if (ret) {
> + DRM_DEV_ERROR(dp->dev,
> + "Failed to idle video %d\n", ret);
> + goto out;
> + }
> }
>
> ret = cdn_dp_config_video(dp);
> @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
> goto out;
> }
>
> - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
> - if (ret) {
> - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret);
> - goto out;
> + if (dp->use_fw_training) {
> + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
> + if (ret) {
> + DRM_DEV_ERROR(dp->dev,
> + "Failed to valid video %d\n", ret);
> + goto out;
> + }
> }
> +
> out:
> mutex_unlock(&dp->lock);
> }
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
> index 46159b2..77a9793 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
> @@ -84,6 +84,7 @@ struct cdn_dp_device {
> bool connected;
> bool active;
> bool suspended;
> + bool use_fw_training;
>
> const struct firmware *fw; /* cdn dp firmware */
> unsigned int fw_version; /* cdn fw version */
> @@ -106,6 +107,7 @@ struct cdn_dp_device {
> u8 ports;
> u8 lanes;
> int active_port;
> + u8 train_set[4];
>
> u8 dpcd[DP_RECEIVER_CAP_SIZE];
> bool sink_has_audio;
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c
> new file mode 100644
> index 0000000..73c3290
> --- /dev/null
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c
> @@ -0,0 +1,420 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
> + * Author: Chris Zhong <zyw@rock-chips.com>
> + */
> +
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/phy/phy.h>
> +#include <soc/rockchip/rockchip_phy_typec.h>
> +
> +#include "cdn-dp-core.h"
> +#include "cdn-dp-reg.h"
> +
> +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp)
> +{
> + struct cdn_dp_port *port = dp->port[dp->active_port];
> + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy);
> +
> + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate);
> + u8 swing = (dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) >>
> + DP_TRAIN_VOLTAGE_SWING_SHIFT;
> + u8 pre_emphasis = (dp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
> + >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
> +
> + tcphy->typec_phy_config(port->phy, rate, dp->link.num_lanes,
> + swing, pre_emphasis);
> +}
> +
> +static int cdn_dp_set_pattern(struct cdn_dp_device *dp, uint8_t dp_train_pat)
> +{
> + u32 phy_config, global_config;
> + int ret;
> + uint8_t pattern = dp_train_pat & DP_TRAINING_PATTERN_MASK;
> +
> + global_config = NUM_LANES(dp->link.num_lanes - 1) | SST_MODE |
> + GLOBAL_EN | RG_EN | ENC_RST_DIS | WR_VHSYNC_FALL;
> +
> + phy_config = DP_TX_PHY_ENCODER_BYPASS(0) |
> + DP_TX_PHY_SKEW_BYPASS(0) |
> + DP_TX_PHY_DISPARITY_RST(0) |
> + DP_TX_PHY_LANE0_SKEW(0) |
> + DP_TX_PHY_LANE1_SKEW(1) |
> + DP_TX_PHY_LANE2_SKEW(2) |
> + DP_TX_PHY_LANE3_SKEW(3) |
> + DP_TX_PHY_10BIT_ENABLE(0);
> +
> + if (pattern != DP_TRAINING_PATTERN_DISABLE) {
> + global_config |= NO_VIDEO;
> + phy_config |= DP_TX_PHY_TRAINING_ENABLE(1) |
> + DP_TX_PHY_SCRAMBLER_BYPASS(1) |
> + DP_TX_PHY_TRAINING_PATTERN(pattern);
> + }
> +
> + ret = cdn_dp_reg_write(dp, DP_FRAMER_GLOBAL_CONFIG, global_config);
> + if (ret) {
> + DRM_ERROR("fail to set DP_FRAMER_GLOBAL_CONFIG, error: %d\n",
> + ret);
> + return ret;
> + }
> +
> + ret = cdn_dp_reg_write(dp, DP_TX_PHY_CONFIG_REG, phy_config);
> + if (ret) {
> + DRM_ERROR("fail to set DP_TX_PHY_CONFIG_REG, error: %d\n",
> + ret);
> + return ret;
> + }
> +
> + ret = cdn_dp_reg_write(dp, DPTX_LANE_EN, BIT(dp->link.num_lanes) - 1);
> + if (ret) {
> + DRM_ERROR("fail to set DPTX_LANE_EN, error: %d\n", ret);
> + return ret;
> + }
> +
> + if (drm_dp_enhanced_frame_cap(dp->dpcd))
> + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 1);
> + else
> + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 0);
> + if (ret)
> + DRM_ERROR("failed to set DPTX_ENHNCD, error: %x\n", ret);
> +
> + return ret;
> +}
> +
> +static u8 cdn_dp_pre_emphasis_max(u8 voltage_swing)
> +{
> + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
> + return DP_TRAIN_PRE_EMPH_LEVEL_3;
> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
> + return DP_TRAIN_PRE_EMPH_LEVEL_2;
> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
> + return DP_TRAIN_PRE_EMPH_LEVEL_1;
> + default:
> + return DP_TRAIN_PRE_EMPH_LEVEL_0;
> + }
> +}
> +
> +static void cdn_dp_get_adjust_train(struct cdn_dp_device *dp,
> + uint8_t link_status[DP_LINK_STATUS_SIZE])
> +{
> + int i;
> + uint8_t v = 0, p = 0;
> + uint8_t preemph_max;
> +
> + for (i = 0; i < dp->link.num_lanes; i++) {
> + v = max(v, drm_dp_get_adjust_request_voltage(link_status, i));
> + p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status,
> + i));
> + }
> +
> + if (v >= VOLTAGE_LEVEL_2)
> + v = VOLTAGE_LEVEL_2 | DP_TRAIN_MAX_SWING_REACHED;
> +
> + preemph_max = cdn_dp_pre_emphasis_max(v);
> + if (p >= preemph_max)
> + p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
> +
> + for (i = 0; i < dp->link.num_lanes; i++)
> + dp->train_set[i] = v | p;
> +}
> +
> +/*
> + * Pick training pattern for channel equalization. Training Pattern 3 for HBR2
> + * or 1.2 devices that support it, Training Pattern 2 otherwise.
> + */
> +static u32 cdn_dp_select_chaneq_pattern(struct cdn_dp_device *dp)
> +{
> + u32 training_pattern = DP_TRAINING_PATTERN_2;
> +
> + /*
> + * cdn dp support HBR2 also support TPS3. TPS3 support is also mandatory
> + * for downstream devices that support HBR2. However, not all sinks
> + * follow the spec.
> + */
> + if (drm_dp_tps3_supported(dp->dpcd))
> + training_pattern = DP_TRAINING_PATTERN_3;
> + else
> + DRM_DEBUG_KMS("5.4 Gbps link rate without sink TPS3 support\n");
> +
> + return training_pattern;
> +}
> +
> +
> +static bool cdn_dp_link_max_vswing_reached(struct cdn_dp_device *dp)
> +{
> + int lane;
> +
> + for (lane = 0; lane < dp->link.num_lanes; lane++)
> + if ((dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED) == 0)
> + return false;
> +
> + return true;
> +}
> +
> +static int cdn_dp_update_link_train(struct cdn_dp_device *dp)
> +{
> + int ret;
> +
> + cdn_dp_set_signal_levels(dp);
> +
> + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
> + dp->train_set, dp->link.num_lanes);
> + if (ret != dp->link.num_lanes)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int cdn_dp_set_link_train(struct cdn_dp_device *dp,
> + uint8_t dp_train_pat)
> +{
> + uint8_t buf[sizeof(dp->train_set) + 1];
> + int ret, len;
> +
> + buf[0] = dp_train_pat;
> + if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
> + DP_TRAINING_PATTERN_DISABLE) {
> + /* don't write DP_TRAINING_LANEx_SET on disable */
> + len = 1;
> + } else {
> + /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
> + memcpy(buf + 1, dp->train_set, dp->link.num_lanes);
> + len = dp->link.num_lanes + 1;
> + }
> +
> + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_PATTERN_SET,
> + buf, len);
> + if (ret != len)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int cdn_dp_reset_link_train(struct cdn_dp_device *dp,
> + uint8_t dp_train_pat)
> +{
> + int ret;
> +
> + memset(dp->train_set, 0, sizeof(dp->train_set));
> +
> + cdn_dp_set_signal_levels(dp);
> +
> + ret = cdn_dp_set_pattern(dp, dp_train_pat);
> + if (ret)
> + return ret;
> +
> + return cdn_dp_set_link_train(dp, dp_train_pat);
> +}
> +
> +/* Enable corresponding port and start training pattern 1 */
> +static int cdn_dp_link_training_clock_recovery(struct cdn_dp_device *dp)
> +{
> + u8 voltage;
> + u8 link_status[DP_LINK_STATUS_SIZE];
> + u32 voltage_tries, max_vswing_tries;
> + int ret;
> +
> + /* clock recovery */
> + ret = cdn_dp_reset_link_train(dp, DP_TRAINING_PATTERN_1 |
> + DP_LINK_SCRAMBLING_DISABLE);
> + if (ret) {
> + DRM_ERROR("failed to start link train\n");
> + return ret;
> + }
> +
> + voltage_tries = 1;
> + max_vswing_tries = 0;
> + for (;;) {
> + drm_dp_link_train_clock_recovery_delay(dp->dpcd);
> + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) !=
> + DP_LINK_STATUS_SIZE) {
> + DRM_ERROR("failed to get link status\n");
> + return -EINVAL;
> + }
> +
> + if (drm_dp_clock_recovery_ok(link_status, dp->link.num_lanes)) {
> + DRM_DEBUG_KMS("clock recovery OK\n");
> + return 0;
> + }
> +
> + if (voltage_tries >= 5) {
> + DRM_DEBUG_KMS("Same voltage tried 5 times\n");
> + return -EINVAL;
> + }
> +
> + if (max_vswing_tries >= 1) {
> + DRM_DEBUG_KMS("Max Voltage Swing reached\n");
> + return -EINVAL;
> + }
> +
> + voltage = dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
> +
> + /* Update training set as requested by target */
> + cdn_dp_get_adjust_train(dp, link_status);
> + if (cdn_dp_update_link_train(dp)) {
> + DRM_ERROR("failed to update link training\n");
> + return -EINVAL;
> + }
> +
> + if ((dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
> + voltage)
> + ++voltage_tries;
> + else
> + voltage_tries = 1;
> +
> + if (cdn_dp_link_max_vswing_reached(dp))
> + ++max_vswing_tries;
> + }
> +}
> +
> +static int cdn_dp_link_training_channel_equalization(struct cdn_dp_device *dp)
> +{
> + int tries, ret;
> + u32 training_pattern;
> + uint8_t link_status[DP_LINK_STATUS_SIZE];
> +
> + training_pattern = cdn_dp_select_chaneq_pattern(dp);
> + training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
> +
> + ret = cdn_dp_set_pattern(dp, training_pattern);
> + if (ret)
> + return ret;
> +
> + ret = cdn_dp_set_link_train(dp, training_pattern);
> + if (ret) {
> + DRM_ERROR("failed to start channel equalization\n");
> + return ret;
> + }
> +
> + for (tries = 0; tries < 5; tries++) {
> + drm_dp_link_train_channel_eq_delay(dp->dpcd);
> + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) !=
> + DP_LINK_STATUS_SIZE) {
> + DRM_ERROR("failed to get link status\n");
> + break;
> + }
> +
> + /* Make sure clock is still ok */
> + if (!drm_dp_clock_recovery_ok(link_status,
> + dp->link.num_lanes)) {
> + DRM_DEBUG_KMS("Clock recovery check failed\n");
> + break;
> + }
> +
> + if (drm_dp_channel_eq_ok(link_status, dp->link.num_lanes)) {
> + DRM_DEBUG_KMS("Channel EQ done\n");
> + return 0;
> + }
> +
> + /* Update training set as requested by target */
> + cdn_dp_get_adjust_train(dp, link_status);
> + if (cdn_dp_update_link_train(dp)) {
> + DRM_ERROR("failed to update link training\n");
> + break;
> + }
> + }
> +
> + /* Try 5 times, else fail and try at lower BW */
> + if (tries == 5)
> + DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
> +
> + return -EINVAL;
> +}
> +
> +static int cdn_dp_stop_link_train(struct cdn_dp_device *dp)
> +{
> + int ret = cdn_dp_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);
> +
> + if (ret)
> + return ret;
> +
> + return cdn_dp_set_link_train(dp, DP_TRAINING_PATTERN_DISABLE);
> +}
> +
> +static int cdn_dp_get_lower_link_rate(struct cdn_dp_device *dp)
> +{
> + switch (dp->link.rate) {
> + case DP_LINK_BW_1_62:
> + return -EINVAL;
> + case DP_LINK_BW_2_7:
> + dp->link.rate = DP_LINK_BW_1_62;
> + break;
> + case DP_LINK_BW_5_4:
> + dp->link.rate = DP_LINK_BW_2_7;
> + break;
> + default:
> + dp->link.rate = DP_LINK_BW_5_4;
> + break;
> + }
> +
> + return 0;
> +}
> +
> +int cdn_dp_software_train_link(struct cdn_dp_device *dp)
> +{
> + int ret, stop_err;
> + u8 link_config[2];
> + u32 rate, sink_max, source_max;
> +
> + ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd,
> + sizeof(dp->dpcd));
> + if (ret < 0) {
> + DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret);
> + return ret;
> + }
> +
> + source_max = dp->lanes;
> + sink_max = drm_dp_max_lane_count(dp->dpcd);
> + dp->link.num_lanes = min(source_max, sink_max);
> +
> + source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE);
> + sink_max = drm_dp_max_link_rate(dp->dpcd);
> + rate = min(source_max, sink_max);
> + dp->link.rate = drm_dp_link_rate_to_bw_code(rate);
> +
> + link_config[0] = 0;
> + link_config[1] = 0;
> + if (dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] & 0x01)
> + link_config[1] = DP_SET_ANSI_8B10B;
> + drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
> +
> + while (true) {
> +
> + /* Write the link configuration data */
> + link_config[0] = dp->link.rate;
> + link_config[1] = dp->link.num_lanes;
> + if (drm_dp_enhanced_frame_cap(dp->dpcd))
> + link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
> + drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, link_config, 2);
> +
> + ret = cdn_dp_link_training_clock_recovery(dp);
> + if (ret) {
> + if (!cdn_dp_get_lower_link_rate(dp))
> + continue;
> +
> + DRM_ERROR("training clock recovery failed: %d\n", ret);
> + break;
> + }
> +
> + ret = cdn_dp_link_training_channel_equalization(dp);
> + if (ret) {
> + if (!cdn_dp_get_lower_link_rate(dp))
> + continue;
> +
> + DRM_ERROR("training channel eq failed: %d\n", ret);
> + break;
> + }
> +
> + break;
> + }
> +
> + stop_err = cdn_dp_stop_link_train(dp);
> + if (stop_err) {
> + DRM_ERROR("stop training fail, error: %d\n", stop_err);
> + return stop_err;
> + }
> +
> + return ret;
> +}
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
> index 979355d..e1273e6 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
> @@ -17,7 +17,9 @@
> #include <linux/delay.h>
> #include <linux/io.h>
> #include <linux/iopoll.h>
> +#include <linux/phy/phy.h>
> #include <linux/reset.h>
> +#include <soc/rockchip/rockchip_phy_typec.h>
>
> #include "cdn-dp-core.h"
> #include "cdn-dp-reg.h"
> @@ -189,7 +191,7 @@ static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id,
> return 0;
> }
>
> -static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
> +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
> {
> u8 msg[6];
>
> @@ -609,6 +611,31 @@ int cdn_dp_train_link(struct cdn_dp_device *dp)
> {
> int ret;
>
> + /*
> + * DP firmware uses fixed phy config values to do training, but some
> + * boards need to adjust these values to fit for their unique hardware
> + * design. So if the phy is using custom config values, do software
> + * link training instead of relying on firmware, if software training
> + * fail, keep firmware training as a fallback if sw training fails.
> + */
> + ret = cdn_dp_software_train_link(dp);
> + if (ret) {
> + DRM_DEV_ERROR(dp->dev,
> + "Failed to do software training %d\n", ret);
> + goto do_fw_training;
> + }
> + ret = cdn_dp_reg_write(dp, SOURCE_HDTX_CAR, 0xf);
> + if (ret) {
> + DRM_DEV_ERROR(dp->dev,
> + "Failed to write SOURCE_HDTX_CAR register %d\n", ret);
> + goto do_fw_training;
> + }
> + dp->use_fw_training = false;
> + return 0;
> +
> +do_fw_training:
> + dp->use_fw_training = true;
> + DRM_DEV_DEBUG_KMS(dp->dev, "use fw training\n");
> ret = cdn_dp_training_start(dp);
> if (ret) {
> DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret);
> @@ -623,7 +650,7 @@ int cdn_dp_train_link(struct cdn_dp_device *dp)
>
> DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate,
> dp->link.num_lanes);
> - return ret;
> + return 0;
> }
>
> int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active)
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
> index 6580b11..3420771 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
> @@ -137,7 +137,7 @@
> #define HPD_EVENT_MASK 0x211c
> #define HPD_EVENT_DET 0x2120
>
> -/* dpyx framer addr */
> +/* dptx framer addr */
> #define DP_FRAMER_GLOBAL_CONFIG 0x2200
> #define DP_SW_RESET 0x2204
> #define DP_FRAMER_TU 0x2208
> @@ -431,6 +431,40 @@
> /* Reference cycles when using lane clock as reference */
> #define LANE_REF_CYC 0x8000
>
> +/* register CM_VID_CTRL */
> +#define LANE_VID_REF_CYC(x) (((x) & (BIT(24) - 1)) << 0)
> +#define NMVID_MEAS_TOLERANCE(x) (((x) & 0xf) << 24)
> +
> +/* register DP_TX_PHY_CONFIG_REG */
> +#define DP_TX_PHY_TRAINING_ENABLE(x) ((x) & 1)
> +#define DP_TX_PHY_TRAINING_TYPE_PRBS7 (0 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_TPS1 (1 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_TPS2 (2 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_TPS3 (3 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_TPS4 (4 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_PLTPAT (5 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_D10_2 (6 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_HBR2CPAT (8 << 1)
> +#define DP_TX_PHY_TRAINING_PATTERN(x) ((x) << 1)
> +#define DP_TX_PHY_SCRAMBLER_BYPASS(x) (((x) & 1) << 5)
> +#define DP_TX_PHY_ENCODER_BYPASS(x) (((x) & 1) << 6)
> +#define DP_TX_PHY_SKEW_BYPASS(x) (((x) & 1) << 7)
> +#define DP_TX_PHY_DISPARITY_RST(x) (((x) & 1) << 8)
> +#define DP_TX_PHY_LANE0_SKEW(x) (((x) & 7) << 9)
> +#define DP_TX_PHY_LANE1_SKEW(x) (((x) & 7) << 12)
> +#define DP_TX_PHY_LANE2_SKEW(x) (((x) & 7) << 15)
> +#define DP_TX_PHY_LANE3_SKEW(x) (((x) & 7) << 18)
> +#define DP_TX_PHY_10BIT_ENABLE(x) (((x) & 1) << 21)
> +
> +/* register DP_FRAMER_GLOBAL_CONFIG */
> +#define NUM_LANES(x) ((x) & 3)
> +#define SST_MODE (0 << 2)
> +#define RG_EN (0 << 4)
> +#define GLOBAL_EN BIT(3)
> +#define NO_VIDEO BIT(5)
> +#define ENC_RST_DIS BIT(6)
> +#define WR_VHSYNC_FALL BIT(7)
> +
> enum voltage_swing_level {
> VOLTAGE_LEVEL_0,
> VOLTAGE_LEVEL_1,
> @@ -476,6 +510,7 @@ int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip);
> int cdn_dp_event_config(struct cdn_dp_device *dp);
> u32 cdn_dp_get_event(struct cdn_dp_device *dp);
> int cdn_dp_get_hpd_status(struct cdn_dp_device *dp);
> +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val);
> ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr,
> u8 *data, u16 len);
> ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr,
> @@ -489,4 +524,5 @@ int cdn_dp_config_video(struct cdn_dp_device *dp);
> int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio);
> int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable);
> int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio);
> +int cdn_dp_software_train_link(struct cdn_dp_device *dp);
> #endif /* _CDN_DP_REG_H */
> --
> 2.7.4
>
Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
^ permalink raw reply
* [PATCH/RFC] ARM: dts: r8a7791: Move enable-method to CPU nodes
From: Geert Uytterhoeven @ 2018-05-23 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180523083746.f4nkz4uhjwfgw7yz@verge.net.au>
Hi Simon,
On Wed, May 23, 2018 at 10:37 AM, Simon Horman <horms@verge.net.au> wrote:
> On Tue, May 22, 2018 at 03:29:25PM +0200, Geert Uytterhoeven wrote:
>> According to Documentation/devicetree/bindings/arm/cpus.txt, the
>> "enable-method" property should be a property of the individual CPU
>> nodes, not of the parent "cpus" node. However, on R-Car M2-W (and on
>> several other arm32 SoCs), the property is tied to the "cpus" node
>> instead.
>>
>> Secondary CPU bringup and CPU hot (un)plug work regardless, as
>> arm_dt_init_cpu_maps() falls back to looking in the "cpus" node.
>>
>> The cpuidle code does not have such a fallback, so it does not detect
>> the enable-method. Note that cpuidle does not support the
>> "renesas,apmu" enable-method yet, so for now this does not make any
>> difference.
>
> Is the implication that if we keep the current binding for cpu nodes
> then at some point we will need to update the cpuidle binding?
If we keep the current binding for cpu nodes, we indeed have to update
(common) Documentation/devicetree/bindings/arm/cpus.txt.
In addition, if we want to add renesas,apmu-based cpuidle support later,
we will have to update the common cpuidle code to look in /cpus, too.
>> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
>> ---
>> Arm64 and powerpc do not have such a fallback, but SH has, like arm32.
>>
>> This is marked RFC, as the alternative is to update the DT bindings to
>> keep the status quo.
>> ---
>> arch/arm/boot/dts/r8a7791.dtsi | 3 ++-
>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
>> index d568bd22d6cbd855..b214cb8f52e47109 100644
>> --- a/arch/arm/boot/dts/r8a7791.dtsi
>> +++ b/arch/arm/boot/dts/r8a7791.dtsi
>> @@ -71,7 +71,6 @@
>> cpus {
>> #address-cells = <1>;
>> #size-cells = <0>;
>> - enable-method = "renesas,apmu";
>>
>> cpu0: cpu at 0 {
>> device_type = "cpu";
>> @@ -83,6 +82,7 @@
>> clock-latency = <300000>; /* 300 us */
>> power-domains = <&sysc R8A7791_PD_CA15_CPU0>;
>> next-level-cache = <&L2_CA15>;
>> + enable-method = "renesas,apmu";
>>
>> /* kHz - uV - OPPs unknown yet */
>> operating-points = <1500000 1000000>,
>> @@ -101,6 +101,7 @@
>> clocks = <&cpg CPG_CORE R8A7791_CLK_Z>;
>> power-domains = <&sysc R8A7791_PD_CA15_CPU1>;
>> next-level-cache = <&L2_CA15>;
>> + enable-method = "renesas,apmu";
>> };
>>
>> L2_CA15: cache-controller-0 {
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 v7 4/5] phy: rockchip-typec: support variable phy config value
From: Enric Balletbo Serra @ 2018-05-23 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527061353-16902-4-git-send-email-hl@rock-chips.com>
2018-05-23 9:42 GMT+02:00 Lin Huang <hl@rock-chips.com>:
> the phy config values used to fix in dp firmware, but some boards
> need change these values to do training and get the better eye diagram
> result. So support that in phy driver.
>
> Signed-off-by: Chris Zhong <zyw@rock-chips.com>
> Signed-off-by: Lin Huang <hl@rock-chips.com>
> ---
> Changes in v2:
> - update patch following Enric suggest
> Changes in v3:
> - delete need_software_training variable
> - add default phy config value, if dts do not define phy config value, use these value
> Changes in v4:
> - rename variable config to tcphy_default_config
> Changes in v5:
> - None
> Changes in v6:
> - split the header file to new patch
> Changes in v7:
> - add default case when check link rate
> - move struct rockchip_typec_phy new element to this patch
>
> drivers/phy/rockchip/phy-rockchip-typec.c | 263 ++++++++++++++++++++++++------
> include/soc/rockchip/rockchip_phy_typec.h | 8 +
> 2 files changed, 218 insertions(+), 53 deletions(-)
>
> diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
> index 795055f..69af90e 100644
> --- a/drivers/phy/rockchip/phy-rockchip-typec.c
> +++ b/drivers/phy/rockchip/phy-rockchip-typec.c
> @@ -324,21 +324,29 @@
> * clock 0: PLL 0 div 1
> * clock 1: PLL 1 div 2
> */
> -#define CLK_PLL_CONFIG 0X30
> +#define CLK_PLL1_DIV1 0x20
> +#define CLK_PLL1_DIV2 0x30
> #define CLK_PLL_MASK 0x33
>
> #define CMN_READY BIT(0)
>
> +#define DP_PLL_CLOCK_ENABLE_ACK BIT(3)
> #define DP_PLL_CLOCK_ENABLE BIT(2)
> +#define DP_PLL_ENABLE_ACK BIT(1)
> #define DP_PLL_ENABLE BIT(0)
> #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8))
> #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8))
> #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8))
> +#define DP_PLL_DATA_RATE_MASK 0xff00
>
> -#define DP_MODE_A0 BIT(4)
> -#define DP_MODE_A2 BIT(6)
> -#define DP_MODE_ENTER_A0 0xc101
> -#define DP_MODE_ENTER_A2 0xc104
> +#define DP_MODE_MASK 0xf
> +#define DP_MODE_ENTER_A0 BIT(0)
> +#define DP_MODE_ENTER_A2 BIT(2)
> +#define DP_MODE_ENTER_A3 BIT(3)
> +#define DP_MODE_A0_ACK BIT(4)
> +#define DP_MODE_A2_ACK BIT(6)
> +#define DP_MODE_A3_ACK BIT(7)
> +#define DP_LINK_RESET_DEASSERTED BIT(8)
>
> #define PHY_MODE_SET_TIMEOUT 100000
>
> @@ -350,6 +358,8 @@
> #define MODE_DFP_USB BIT(1)
> #define MODE_DFP_DP BIT(2)
>
> +#define DP_DEFAULT_RATE 162000
> +
> struct phy_reg {
> u16 value;
> u32 addr;
> @@ -372,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = {
> { 0x8, CMN_DIAG_PLL0_LF_PROG },
> };
>
> -struct phy_reg dp_pll_cfg[] = {
> +struct phy_reg dp_pll_rbr_cfg[] = {
> { 0xf0, CMN_PLL1_VCOCAL_INIT },
> { 0x18, CMN_PLL1_VCOCAL_ITER },
> { 0x30b9, CMN_PLL1_VCOCAL_START },
> - { 0x21c, CMN_PLL1_INTDIV },
> + { 0x87, CMN_PLL1_INTDIV },
> { 0, CMN_PLL1_FRACDIV },
> - { 0x5, CMN_PLL1_HIGH_THR },
> - { 0x35, CMN_PLL1_SS_CTRL1 },
> - { 0x7f1e, CMN_PLL1_SS_CTRL2 },
> + { 0x22, CMN_PLL1_HIGH_THR },
> + { 0x8000, CMN_PLL1_SS_CTRL1 },
> + { 0, CMN_PLL1_SS_CTRL2 },
> { 0x20, CMN_PLL1_DSM_DIAG },
> { 0, CMN_PLLSM1_USER_DEF_CTRL },
> { 0, CMN_DIAG_PLL1_OVRD },
> @@ -391,9 +401,52 @@ struct phy_reg dp_pll_cfg[] = {
> { 0x8, CMN_DIAG_PLL1_LF_PROG },
> { 0x100, CMN_DIAG_PLL1_PTATIS_TUNE1 },
> { 0x7, CMN_DIAG_PLL1_PTATIS_TUNE2 },
> - { 0x4, CMN_DIAG_PLL1_INCLK_CTRL },
> + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL },
> };
>
> +struct phy_reg dp_pll_hbr_cfg[] = {
> + { 0xf0, CMN_PLL1_VCOCAL_INIT },
> + { 0x18, CMN_PLL1_VCOCAL_ITER },
> + { 0x30b4, CMN_PLL1_VCOCAL_START },
> + { 0xe1, CMN_PLL1_INTDIV },
> + { 0, CMN_PLL1_FRACDIV },
> + { 0x5, CMN_PLL1_HIGH_THR },
> + { 0x8000, CMN_PLL1_SS_CTRL1 },
> + { 0, CMN_PLL1_SS_CTRL2 },
> + { 0x20, CMN_PLL1_DSM_DIAG },
> + { 0x1000, CMN_PLLSM1_USER_DEF_CTRL },
> + { 0, CMN_DIAG_PLL1_OVRD },
> + { 0, CMN_DIAG_PLL1_FBH_OVRD },
> + { 0, CMN_DIAG_PLL1_FBL_OVRD },
> + { 0x7, CMN_DIAG_PLL1_V2I_TUNE },
> + { 0x45, CMN_DIAG_PLL1_CP_TUNE },
> + { 0x8, CMN_DIAG_PLL1_LF_PROG },
> + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE1 },
> + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE2 },
> + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL },
> +};
> +
> +struct phy_reg dp_pll_hbr2_cfg[] = {
> + { 0xf0, CMN_PLL1_VCOCAL_INIT },
> + { 0x18, CMN_PLL1_VCOCAL_ITER },
> + { 0x30b4, CMN_PLL1_VCOCAL_START },
> + { 0xe1, CMN_PLL1_INTDIV },
> + { 0, CMN_PLL1_FRACDIV },
> + { 0x5, CMN_PLL1_HIGH_THR },
> + { 0x8000, CMN_PLL1_SS_CTRL1 },
> + { 0, CMN_PLL1_SS_CTRL2 },
> + { 0x20, CMN_PLL1_DSM_DIAG },
> + { 0x1000, CMN_PLLSM1_USER_DEF_CTRL },
> + { 0, CMN_DIAG_PLL1_OVRD },
> + { 0, CMN_DIAG_PLL1_FBH_OVRD },
> + { 0, CMN_DIAG_PLL1_FBL_OVRD },
> + { 0x7, CMN_DIAG_PLL1_V2I_TUNE },
> + { 0x45, CMN_DIAG_PLL1_CP_TUNE },
> + { 0x8, CMN_DIAG_PLL1_LF_PROG },
> + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE1 },
> + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE2 },
> + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL },
> +};
> static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
> {
> .reg = 0xff7c0000,
> @@ -418,6 +471,24 @@ static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
> { /* sentinel */ }
> };
>
> +/* default phy config */
> +static const struct phy_config tcphy_default_config[3][4] = {
> + {{ .swing = 0x2a, .pe = 0x00 },
> + { .swing = 0x1f, .pe = 0x15 },
> + { .swing = 0x14, .pe = 0x22 },
> + { .swing = 0x02, .pe = 0x2b } },
> +
> + {{ .swing = 0x21, .pe = 0x00 },
> + { .swing = 0x12, .pe = 0x15 },
> + { .swing = 0x02, .pe = 0x22 },
> + { .swing = 0, .pe = 0 } },
> +
> + {{ .swing = 0x15, .pe = 0x00 },
> + { .swing = 0x00, .pe = 0x15 },
> + { .swing = 0, .pe = 0 },
> + { .swing = 0, .pe = 0 } },
> +};
> +
> static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy)
> {
> u32 i, rdata;
> @@ -439,7 +510,7 @@ static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy)
>
> rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
> rdata &= ~CLK_PLL_MASK;
> - rdata |= CLK_PLL_CONFIG;
> + rdata |= CLK_PLL1_DIV2;
> writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
> }
>
> @@ -453,17 +524,45 @@ static void tcphy_cfg_usb3_pll(struct rockchip_typec_phy *tcphy)
> tcphy->base + usb3_pll_cfg[i].addr);
> }
>
> -static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
> +static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy, int link_rate)
> {
> - u32 i;
> + struct phy_reg *phy_cfg;
> + u32 clk_ctrl;
> + u32 i, cfg_size, hsclk_sel;
> +
> + hsclk_sel = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
> + hsclk_sel &= ~CLK_PLL_MASK;
> +
> + switch (link_rate) {
> + case 540000:
> + clk_ctrl = DP_PLL_DATA_RATE_HBR2;
> + hsclk_sel |= CLK_PLL1_DIV1;
> + phy_cfg = dp_pll_hbr2_cfg;
> + cfg_size = ARRAY_SIZE(dp_pll_hbr2_cfg);
> + break;
> + case 270000:
> + clk_ctrl = DP_PLL_DATA_RATE_HBR;
> + hsclk_sel |= CLK_PLL1_DIV2;
> + phy_cfg = dp_pll_hbr_cfg;
> + cfg_size = ARRAY_SIZE(dp_pll_hbr_cfg);
> + break;
> + case 162000:
> + default:
> + clk_ctrl = DP_PLL_DATA_RATE_RBR;
> + hsclk_sel |= CLK_PLL1_DIV2;
> + phy_cfg = dp_pll_rbr_cfg;
> + cfg_size = ARRAY_SIZE(dp_pll_rbr_cfg);
> + break;
> + }
>
> - /* set the default mode to RBR */
> - writel(DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE | DP_PLL_DATA_RATE_RBR,
> - tcphy->base + DP_CLK_CTL);
> + clk_ctrl |= DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE;
> + writel(clk_ctrl, tcphy->base + DP_CLK_CTL);
> +
> + writel(hsclk_sel, tcphy->base + CMN_DIAG_HSCLK_SEL);
>
> /* load the configuration of PLL1 */
> - for (i = 0; i < ARRAY_SIZE(dp_pll_cfg); i++)
> - writel(dp_pll_cfg[i].value, tcphy->base + dp_pll_cfg[i].addr);
> + for (i = 0; i < cfg_size; i++)
> + writel(phy_cfg[i].value, tcphy->base + phy_cfg[i].addr);
> }
>
> static void tcphy_tx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane)
> @@ -490,9 +589,10 @@ static void tcphy_rx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane)
> writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
> }
>
> -static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane)
> +static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, int link_rate,
> + u8 swing, u8 pre_emp, u32 lane)
> {
> - u16 rdata;
> + u16 val;
>
> writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane));
> writel(0x6799, tcphy->base + TX_PSC_A0(lane));
> @@ -500,25 +600,32 @@ static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane)
> writel(0x98, tcphy->base + TX_PSC_A2(lane));
> writel(0x98, tcphy->base + TX_PSC_A3(lane));
>
> - writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
> - writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane));
> - writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane));
> - writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane));
> - writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane));
> - writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane));
> - writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane));
> - writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane));
> - writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane));
> - writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane));
> - writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane));
> - writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane));
> -
> - writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
> - writel(0x400, tcphy->base + TX_DIAG_TX_DRV(lane));
> -
> - rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
> - rdata = (rdata & 0x8fff) | 0x6000;
> - writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
> + writel(tcphy->config[swing][pre_emp].swing,
> + tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
> + writel(tcphy->config[swing][pre_emp].pe,
> + tcphy->base + TX_TXCC_CPOST_MULT_00(lane));
> +
> + if (swing == 2 && pre_emp == 0 && link_rate != 540000) {
> + writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane));
> + writel(0x13c, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
> + } else {
> + writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
> + writel(0x0400, tcphy->base + TX_DIAG_TX_DRV(lane));
> + }
> +
> + val = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
> + val = val & 0x8fff;
> + switch (link_rate) {
> + case 540000:
> + val |= (4 << 12);
> + break;
> + case 162000:
> + case 270000:
> + default:
> + val |= (6 << 12);
> + break;
> + }
> + writel(val, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
> }
>
> static inline int property_enable(struct rockchip_typec_phy *tcphy,
> @@ -709,30 +816,33 @@ static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
> tcphy_cfg_24m(tcphy);
>
> if (mode == MODE_DFP_DP) {
> - tcphy_cfg_dp_pll(tcphy);
> + tcphy_cfg_dp_pll(tcphy, DP_DEFAULT_RATE);
> for (i = 0; i < 4; i++)
> - tcphy_dp_cfg_lane(tcphy, i);
> + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, i);
>
> writel(PIN_ASSIGN_C_E, tcphy->base + PMA_LANE_CFG);
> } else {
> tcphy_cfg_usb3_pll(tcphy);
> - tcphy_cfg_dp_pll(tcphy);
> + tcphy_cfg_dp_pll(tcphy, DP_DEFAULT_RATE);
> if (tcphy->flip) {
> tcphy_tx_usb3_cfg_lane(tcphy, 3);
> tcphy_rx_usb3_cfg_lane(tcphy, 2);
> - tcphy_dp_cfg_lane(tcphy, 0);
> - tcphy_dp_cfg_lane(tcphy, 1);
> + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 0);
> + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 1);
> } else {
> tcphy_tx_usb3_cfg_lane(tcphy, 0);
> tcphy_rx_usb3_cfg_lane(tcphy, 1);
> - tcphy_dp_cfg_lane(tcphy, 2);
> - tcphy_dp_cfg_lane(tcphy, 3);
> + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 2);
> + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 3);
> }
>
> writel(PIN_ASSIGN_D_F, tcphy->base + PMA_LANE_CFG);
> }
>
> - writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
> + val = readl(tcphy->base + DP_MODE_CTL);
> + val &= ~DP_MODE_MASK;
> + val |= DP_MODE_ENTER_A2 | DP_LINK_RESET_DEASSERTED;
> + writel(val, tcphy->base + DP_MODE_CTL);
>
> reset_control_deassert(tcphy->uphy_rst);
>
> @@ -945,7 +1055,7 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
> property_enable(tcphy, &cfg->uphy_dp_sel, 1);
>
> ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
> - val, val & DP_MODE_A2, 1000,
> + val, val & DP_MODE_A2_ACK, 1000,
> PHY_MODE_SET_TIMEOUT);
> if (ret < 0) {
> dev_err(tcphy->dev, "failed to wait TCPHY enter A2\n");
> @@ -954,13 +1064,19 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
>
> tcphy_dp_aux_calibration(tcphy);
>
> - writel(DP_MODE_ENTER_A0, tcphy->base + DP_MODE_CTL);
> + /* enter A0 mode */
> + val = readl(tcphy->base + DP_MODE_CTL);
> + val &= ~DP_MODE_MASK;
> + val |= DP_MODE_ENTER_A0;
> + writel(val, tcphy->base + DP_MODE_CTL);
>
> ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
> - val, val & DP_MODE_A0, 1000,
> + val, val & DP_MODE_A0_ACK, 1000,
> PHY_MODE_SET_TIMEOUT);
> if (ret < 0) {
> - writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
> + val &= ~DP_MODE_MASK;
> + val |= DP_MODE_ENTER_A2;
> + writel(val, tcphy->base + DP_MODE_CTL);
> dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
> goto power_on_finish;
> }
> @@ -978,6 +1094,7 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
> static int rockchip_dp_phy_power_off(struct phy *phy)
> {
> struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
> + u32 val;
>
> mutex_lock(&tcphy->lock);
>
> @@ -986,7 +1103,10 @@ static int rockchip_dp_phy_power_off(struct phy *phy)
>
> tcphy->mode &= ~MODE_DFP_DP;
>
> - writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
> + val = readl(tcphy->base + DP_MODE_CTL);
> + val &= ~DP_MODE_MASK;
> + val |= DP_MODE_ENTER_A2;
> + writel(val, tcphy->base + DP_MODE_CTL);
>
> if (tcphy->mode == MODE_DISCONNECT)
> tcphy_phy_deinit(tcphy);
> @@ -1002,9 +1122,35 @@ static const struct phy_ops rockchip_dp_phy_ops = {
> .owner = THIS_MODULE,
> };
>
> +static int typec_dp_phy_config(struct phy *phy, int link_rate,
> + int lanes, u8 swing, u8 pre_emp)
> +{
> + struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
> + u8 i;
> +
> + tcphy_cfg_dp_pll(tcphy, link_rate);
> +
> + if (tcphy->mode == MODE_DFP_DP) {
> + for (i = 0; i < 4; i++)
> + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, i);
> + } else {
> + if (tcphy->flip) {
> + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 0);
> + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 1);
> + } else {
> + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 2);
> + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 3);
> + }
> + }
> +
> + return 0;
> +}
> +
> static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
> struct device *dev)
> {
> + int ret;
> +
> tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
> "rockchip,grf");
> if (IS_ERR(tcphy->grf_regs)) {
> @@ -1042,6 +1188,16 @@ static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
> return PTR_ERR(tcphy->tcphy_rst);
> }
>
> + /*
> + * check if phy_config pass from dts, if no,
> + * use default phy config value.
> + */
> + ret = of_property_read_u32_array(dev->of_node, "rockchip,phy-config",
> + (u32 *)tcphy->config, sizeof(tcphy->config) / sizeof(u32));
> + if (ret)
> + memcpy(tcphy->config, tcphy_default_config,
> + sizeof(tcphy->config));
> +
> return 0;
> }
>
> @@ -1126,6 +1282,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
> }
> }
>
> + tcphy->typec_phy_config = typec_dp_phy_config;
> pm_runtime_enable(dev);
>
> for_each_available_child_of_node(np, child_np) {
> diff --git a/include/soc/rockchip/rockchip_phy_typec.h b/include/soc/rockchip/rockchip_phy_typec.h
> index 4afe039..8e45c4d 100644
> --- a/include/soc/rockchip/rockchip_phy_typec.h
> +++ b/include/soc/rockchip/rockchip_phy_typec.h
> @@ -35,6 +35,11 @@ struct rockchip_usb3phy_port_cfg {
> struct usb3phy_reg uphy_dp_sel;
> };
>
> +struct phy_config {
> + int swing;
> + int pe;
> +};
> +
> struct rockchip_typec_phy {
> struct device *dev;
> void __iomem *base;
> @@ -50,6 +55,9 @@ struct rockchip_typec_phy {
> struct mutex lock;
> bool flip;
> u8 mode;
> + struct phy_config config[3][4];
> + int (*typec_phy_config)(struct phy *phy, int link_rate,
> + int lanes, u8 swing, u8 pre_emp);
> };
>
> #endif
> --
> 2.7.4
>
Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
^ permalink raw reply
* [PATCH v7 3/5] soc: rockchip: split rockchip_typec_phy struct to separate header
From: Enric Balletbo Serra @ 2018-05-23 8:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527061353-16902-3-git-send-email-hl@rock-chips.com>
2018-05-23 9:42 GMT+02:00 Lin Huang <hl@rock-chips.com>:
> we may use rockchip_phy_typec struct in other driver, so split
> it to separate header.
>
> Signed-off-by: Lin Huang <hl@rock-chips.com>
> ---
> Changes in v2:
> - None
> Changes in v3:
> - None
> Changes in v4:
> - None
> Changes in v5:
> - None
> Changes in v6:
> - new patch here
> Changes in v7:
> - move new element to next patch
>
> drivers/phy/rockchip/phy-rockchip-typec.c | 47 +-------------------------
> include/soc/rockchip/rockchip_phy_typec.h | 55 +++++++++++++++++++++++++++++++
> 2 files changed, 56 insertions(+), 46 deletions(-)
> create mode 100644 include/soc/rockchip/rockchip_phy_typec.h
>
> diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
> index 76a4b58..795055f 100644
> --- a/drivers/phy/rockchip/phy-rockchip-typec.c
> +++ b/drivers/phy/rockchip/phy-rockchip-typec.c
> @@ -63,6 +63,7 @@
>
> #include <linux/mfd/syscon.h>
> #include <linux/phy/phy.h>
> +#include <soc/rockchip/rockchip_phy_typec.h>
>
> #define CMN_SSM_BANDGAP (0x21 << 2)
> #define CMN_SSM_BIAS (0x22 << 2)
> @@ -349,52 +350,6 @@
> #define MODE_DFP_USB BIT(1)
> #define MODE_DFP_DP BIT(2)
>
> -struct usb3phy_reg {
> - u32 offset;
> - u32 enable_bit;
> - u32 write_enable;
> -};
> -
> -/**
> - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration.
> - * @reg: the base address for usb3-phy config.
> - * @typec_conn_dir: the register of type-c connector direction.
> - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable.
> - * @external_psm: the register of type-c phy external psm clock.
> - * @pipe_status: the register of type-c phy pipe status.
> - * @usb3_host_disable: the register of type-c usb3 host disable.
> - * @usb3_host_port: the register of type-c usb3 host port.
> - * @uphy_dp_sel: the register of type-c phy DP select control.
> - */
> -struct rockchip_usb3phy_port_cfg {
> - unsigned int reg;
> - struct usb3phy_reg typec_conn_dir;
> - struct usb3phy_reg usb3tousb2_en;
> - struct usb3phy_reg external_psm;
> - struct usb3phy_reg pipe_status;
> - struct usb3phy_reg usb3_host_disable;
> - struct usb3phy_reg usb3_host_port;
> - struct usb3phy_reg uphy_dp_sel;
> -};
> -
> -struct rockchip_typec_phy {
> - struct device *dev;
> - void __iomem *base;
> - struct extcon_dev *extcon;
> - struct regmap *grf_regs;
> - struct clk *clk_core;
> - struct clk *clk_ref;
> - struct reset_control *uphy_rst;
> - struct reset_control *pipe_rst;
> - struct reset_control *tcphy_rst;
> - const struct rockchip_usb3phy_port_cfg *port_cfgs;
> - /* mutex to protect access to individual PHYs */
> - struct mutex lock;
> -
> - bool flip;
> - u8 mode;
> -};
> -
> struct phy_reg {
> u16 value;
> u32 addr;
> diff --git a/include/soc/rockchip/rockchip_phy_typec.h b/include/soc/rockchip/rockchip_phy_typec.h
> new file mode 100644
> index 0000000..4afe039
> --- /dev/null
> +++ b/include/soc/rockchip/rockchip_phy_typec.h
> @@ -0,0 +1,55 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
> + * Author: Lin Huang <hl@rock-chips.com>
> + */
> +
> +#ifndef __SOC_ROCKCHIP_PHY_TYPEC_H
> +#define __SOC_ROCKCHIP_PHY_TYPEC_H
> +
> +struct usb3phy_reg {
> + u32 offset;
> + u32 enable_bit;
> + u32 write_enable;
> +};
> +
> +/**
> + * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration.
> + * @reg: the base address for usb3-phy config.
> + * @typec_conn_dir: the register of type-c connector direction.
> + * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable.
> + * @external_psm: the register of type-c phy external psm clock.
> + * @pipe_status: the register of type-c phy pipe status.
> + * @usb3_host_disable: the register of type-c usb3 host disable.
> + * @usb3_host_port: the register of type-c usb3 host port.
> + * @uphy_dp_sel: the register of type-c phy DP select control.
> + */
> +struct rockchip_usb3phy_port_cfg {
> + unsigned int reg;
> + struct usb3phy_reg typec_conn_dir;
> + struct usb3phy_reg usb3tousb2_en;
> + struct usb3phy_reg external_psm;
> + struct usb3phy_reg pipe_status;
> + struct usb3phy_reg usb3_host_disable;
> + struct usb3phy_reg usb3_host_port;
> + struct usb3phy_reg uphy_dp_sel;
> +};
> +
> +struct rockchip_typec_phy {
> + struct device *dev;
> + void __iomem *base;
> + struct extcon_dev *extcon;
> + struct regmap *grf_regs;
> + struct clk *clk_core;
> + struct clk *clk_ref;
> + struct reset_control *uphy_rst;
> + struct reset_control *pipe_rst;
> + struct reset_control *tcphy_rst;
> + const struct rockchip_usb3phy_port_cfg *port_cfgs;
> + /* mutex to protect access to individual PHYs */
> + struct mutex lock;
> + bool flip;
> + u8 mode;
> +};
> +
> +#endif
> --
> 2.7.4
>
Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
^ permalink raw reply
* [PATCHv4 05/10] arm64/cpufeature: detect pointer authentication
From: Suzuki K Poulose @ 2018-05-23 8:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503132031.25705-6-mark.rutland@arm.com>
Mark,
On 03/05/18 14:20, Mark Rutland wrote:
> So that we can dynamically handle the presence of pointer authentication
> functionality, wire up probing code in cpufeature.c.
>
> From ARMv8.3 onwards, ID_AA64ISAR1 is no longer entirely RES0, and now
> has four fields describing the presence of pointer authentication
> functionality:
>
> * APA - address authentication present, using an architected algorithm
> * API - address authentication present, using an IMP DEF algorithm
> * GPA - generic authentication present, using an architected algorithm
> * GPI - generic authentication present, using an IMP DEF algorithm
>
> For the moment we only care about address authentication, so we only
> need to check APA and API. It is assumed that if all CPUs support an IMP
> DEF algorithm, the same algorithm is used across all CPUs.
>
> Note that when we implement KVM support, we will also need to ensure
> that CPUs have uniform support for GPA and GPI.
>
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> ---
> arch/arm64/include/asm/cpucaps.h | 5 ++++-
> arch/arm64/kernel/cpufeature.c | 47 ++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 51 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
> index bc51b72fafd4..9dcb4d1b14f5 100644
> --- a/arch/arm64/include/asm/cpucaps.h
> +++ b/arch/arm64/include/asm/cpucaps.h
> @@ -48,7 +48,10 @@
> #define ARM64_HAS_CACHE_IDC 27
> #define ARM64_HAS_CACHE_DIC 28
> #define ARM64_HW_DBM 29
> +#define ARM64_HAS_ADDRESS_AUTH_ARCH 30
> +#define ARM64_HAS_ADDRESS_AUTH_IMP_DEF 31
Where are these caps used ? I couldn't find anything in the series
that uses them. Otherwise looks good to me.
Cheers
Suzuki
^ permalink raw reply
* [PATCH 01/14] memory: ti-emif-sram: Add resume function to recopy sram code
From: Keerthy @ 2018-05-23 8:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d52373eb-1707-17ff-fabb-9f7200cf54c0@ti.com>
On Monday 16 April 2018 03:59 PM, Keerthy wrote:
>
>
> On Thursday 12 April 2018 10:14 PM, santosh.shilimkar at oracle.com wrote:
>> On 4/11/18 9:53 PM, Keerthy wrote:
>>> From: Dave Gerlach <d-gerlach@ti.com>
>>>
>>> After an RTC+DDR cycle we lose sram context so emif pm functions present
>>> in sram are lost. We can check if the first byte of the original
>>> code in DDR contains the same first byte as the code in sram, and if
>>> they do not match we know we have lost context and must recopy the
>>> functions to the previous address to maintain PM functionality.
>>>
>>> Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
>>> Signed-off-by: Keerthy <j-keerthy@ti.com>
>>> ---
>>> ? drivers/memory/ti-emif-pm.c | 24 ++++++++++++++++++++++++
>>> ? 1 file changed, 24 insertions(+)
>>>
>>> diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
>>> index 632651f..ec4a62c 100644
>>> --- a/drivers/memory/ti-emif-pm.c
>>> +++ b/drivers/memory/ti-emif-pm.c
>>> @@ -249,6 +249,25 @@ int ti_emif_get_mem_type(void)
>>> ? };
>>> ? MODULE_DEVICE_TABLE(of, ti_emif_of_match);
>>> ? +#ifdef CONFIG_PM_SLEEP
>>> +static int ti_emif_resume(struct device *dev)
>>> +{
>>> +??? unsigned long tmp =
>>> +??????????? __raw_readl((void *)emif_instance->ti_emif_sram_virt);
>>> +
>>> +??? /*
>>> +???? * Check to see if what we are copying is already present in the
>>> +???? * first byte at the destination, only copy if it is not which
>>> +???? * indicates we have lost context and sram no longer contains
>>> +???? * the PM code
>>> +???? */
>>
>>> +??? if (tmp != ti_emif_sram)
>>> +??????? ti_emif_push_sram(dev, emif_instance);
>>> +
>>> +??? return 0;
>>> +}
>>> +#endif /* CONFIG_PM_SLEEP */
>> Instead of this indirect method , why can't just check the previous
>> deep sleep mode and based on that do copy or not. EMIF power status
>> register should have something like that ?
>
> I will check if we have a register that tells the previous state of sram.
Unfortunately i do not see any such register for knowing SRAM previous
state in am43 TRM and hence this indirect way of knowing.
http://www.ti.com/lit/ug/spruhl7h/spruhl7h.pdf
>
>>
>> Another minor point is even though there is nothing to do in suspend,
>> might be good to have a callback with comment that nothing to do with
>> some explanation why not. Don't have strong preference but may for
>> better readability.
I can add a blank suspend call with comment
"The contents are already present in DDR hence no need to explicitly save"
The comment in resume function pretty much explains the above. So let me
know if i need to add the suspend callback.
Regards,
Keerthy
>
> Okay. Thanks a lot for the quick feedback!
>
>>
>> Regards,
>> Santosh
>>
>>
^ permalink raw reply
* [rjarzmik:test/daniel 23/34] sound/arm/pxa2xx-ac97.c:27:10: fatal error: mach/regs-ac97.h: No such file or directory
From: kbuild test robot @ 2018-05-23 8:46 UTC (permalink / raw)
To: linux-arm-kernel
tree: https://github.com/rjarzmik/linux test/daniel
head: f495e2dbc482d8f01a1ee20e86284ee9c0c8fa98
commit: 4cd654b13b9bcc0f206d414497b798ed42df573a [23/34] HACK: select SND_PXA_SOC_SSP for SND_SIMPLE_CARD
config: x86_64-randconfig-s3-05231547 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
reproduce:
git checkout 4cd654b13b9bcc0f206d414497b798ed42df573a
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
>> sound/arm/pxa2xx-ac97.c:27:10: fatal error: mach/regs-ac97.h: No such file or directory
#include <mach/regs-ac97.h>
^~~~~~~~~~~~~~~~~~
compilation terminated.
--
>> sound/soc/pxa/pxa2xx-i2s.c:28:10: fatal error: mach/hardware.h: No such file or directory
#include <mach/hardware.h>
^~~~~~~~~~~~~~~~~
compilation terminated.
vim +27 sound/arm/pxa2xx-ac97.c
2c484df0 Takashi Iwai 2005-06-30 26
1f017a99 Eric Miao 2008-11-28 @27 #include <mach/regs-ac97.h>
a09e64fb Russell King 2008-08-05 28 #include <mach/audio.h>
2c484df0 Takashi Iwai 2005-06-30 29
:::::: The code at line 27 was first introduced by commit
:::::: 1f017a9964c5b3b9581d3a5732110cb1e0444281 [ARM] pxa: move AC97 register definitions into dedicated regs-ac97.h
:::::: TO: Eric Miao <eric.miao@marvell.com>
:::::: CC: Eric Miao <eric.miao@marvell.com>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 31184 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180523/2435dd78/attachment-0001.gz>
^ permalink raw reply
* [PATCH] pinctrl: armada-37xx: Fix spurious irq management
From: Gregory CLEMENT @ 2018-05-23 8:44 UTC (permalink / raw)
To: linux-arm-kernel
From: Terry Zhou <bjzhou@marvell.com>
Until now, if we found spurious irq in irq_handler, we only updated the
status in register but not the status in the code. Due to this the system
will got stuck dues to the infinite loop
[gregory.clement at bootlin.com: update comment and add fix and stable tags]
Fixes: 30ac0d3b0702 ("pinctrl: armada-37xx: Add edge both type gpio irq support")
Cc: <stable@vger.kernel.org>
Signed-off-by: Terry Zhou <bjzhou@marvell.com>
Reviewed-by: Gregory CLEMENT <gregory.clement@bootlin.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
---
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index 5b63248c8209..7bef929bd7fe 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -679,12 +679,13 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
writel(1 << hwirq,
info->base +
IRQ_STATUS + 4 * i);
- continue;
+ goto update_status;
}
}
generic_handle_irq(virq);
+update_status:
/* Update status in case a new IRQ appears */
spin_lock_irqsave(&info->irq_lock, flags);
status = readl_relaxed(info->base +
--
2.17.0
^ 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