* [PATCH v2] ARM: da850: Fix LEGO EV3 battery voltage gpio
From: David Lechner @ 2017-12-03 21:58 UTC (permalink / raw)
To: linux-arm-kernel
This fixes the battery voltage monitoring gpio-hog settings.
When the gpio is low, it turns off the battery voltage to the ADC chip.
However, this needs to be on all of the time so that we can monitor
battery voltage.
Also, there was a typo that prevented pinmuxing from working correctly.
Signed-off-by: David Lechner <david@lechnology.com>
---
arch/arm/boot/dts/da850-lego-ev3.dts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/da850-lego-ev3.dts b/arch/arm/boot/dts/da850-lego-ev3.dts
index 65ceaa3..a4ee12f 100644
--- a/arch/arm/boot/dts/da850-lego-ev3.dts
+++ b/arch/arm/boot/dts/da850-lego-ev3.dts
@@ -178,7 +178,7 @@
*/
battery {
pinctrl-names = "default";
- pintctrl-0 = <&battery_pins>;
+ pinctrl-0 = <&battery_pins>;
compatible = "lego,ev3-battery";
io-channels = <&adc 4>, <&adc 3>;
io-channel-names = "voltage", "current";
@@ -465,7 +465,7 @@
batt_volt_en {
gpio-hog;
gpios = <6 GPIO_ACTIVE_HIGH>;
- output-low;
+ output-high;
};
/* Don't impede Bluetooth clock signal */
--
2.7.4
^ permalink raw reply related
* linux-next: Signed-off-by missing for commit in the arm-soc tree
From: Stephen Rothwell @ 2017-12-03 21:32 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
Commit
5f56b7f4854a ("Revert "Merge tag 'scpi-updates-4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into next/drivers"")
is missing a Signed-off-by from its author or committer.
Reverts are commits as well and so need an explanation of why they
are done and Signed-off-by tags.
--
Cheers,
Stephen Rothwell
^ permalink raw reply
* [PATCH 1/2] dt-bindings: trivial: add tfa9879 device
From: Fabio Estevam @ 2017-12-03 21:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5ec7ae30-eeac-3cf8-15ad-f6c3a110c5d7@axentia.se>
On Sun, Dec 3, 2017 at 6:53 PM, Peter Rosin <peda@axentia.se> wrote:
> That's funny, because I get the below on both 4.14 and 4.15-rc1. And I
> expect the same ever since the driver was added some 3 years ago.
>
> $ scripts/get_maintainer.pl your-patch-from[1].diff | grep Peter
> Peter Rosin <peda@axentia.se> (maintainer:NXP TFA9879 DRIVER)
You are right.
I tried ./scripts/get_maintainer.pl
Documentation/devicetree/bindings/sound/tfa9879.txt
in 4.15-rc1.
^ permalink raw reply
* [PATCH 1/2] dt-bindings: trivial: add tfa9879 device
From: Peter Rosin @ 2017-12-03 20:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOMZO5AE++an6MnagrWoL4qwkDJaqtg_qJ5UKX3PB7sw1cTeiA@mail.gmail.com>
On 2017-12-03 12:12, Fabio Estevam wrote:
> Hi Peter,
>
> On Sun, Dec 3, 2017 at 4:59 AM, Peter Rosin <peda@axentia.se> wrote:
>
>> Right. However, the patch adding that should have been sent to me, the
>> maintainer of the driver. That is carefully recorded in MAINTAINERS. So,
>> forgive me for assuming that nothing had changed in the driver behind my
>> back.
>>
>> Had that patch been sent my way as it should have been, I would have
>> insisted that maintenance of the bindings had been kept together with
>> the maintenance of the driver.
>
> When I sent this patch ./scripts/get_maintainer.pl did lot list your
> name, so that's why I did not put you on Cc, sorry.
>
> 4.15-rc1 still does not list you, but linux-next does.
That's funny, because I get the below on both 4.14 and 4.15-rc1. And I
expect the same ever since the driver was added some 3 years ago.
$ scripts/get_maintainer.pl your-patch-from[1].diff | grep Peter
Peter Rosin <peda@axentia.se> (maintainer:NXP TFA9879 DRIVER)
[1] https://patchwork.ozlabs.org/patch/815930/
By the way, scripts/checkpatch.pl on that patch reports
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
> Would you like me to send the following patch so that new binding
> updates go to you?
Naahh, I'll claim it myself, that way I can clean up some nits in the
actual file while at it...
Cheers,
Peter
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -9808,6 +9808,7 @@ NXP TFA9879 DRIVER
> M: Peter Rosin <peda@axentia.se>
> L: alsa-devel at alsa-project.org (moderated for non-subscribers)
> S: Maintained
> +F: Documentation/devicetree/bindings/sound/tfa9879.txt
> F: sound/soc/codecs/tfa9879*
>
^ permalink raw reply
* [PATCH 11/37] KVM: arm64: Improve debug register save/restore flow
From: Christoffer Dall @ 2017-12-03 20:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203134958.b5zfdv2mbu6lr6gj@hawk.localdomain>
On Sun, Dec 03, 2017 at 02:49:58PM +0100, Andrew Jones wrote:
> On Fri, Dec 01, 2017 at 06:52:03PM +0100, Christoffer Dall wrote:
> > On Tue, Nov 07, 2017 at 03:48:57PM +0100, Andrew Jones wrote:
> > > On Thu, Oct 12, 2017 at 12:41:15PM +0200, Christoffer Dall wrote:
> > > > Instead of having multiple calls from the world switch path to the debug
> > > > logic, each figuring out if the dirty bit is set and if we should
> > > > save/restore the debug registes, let's just provide two hooks to the
> > > > debug save/restore functionality, one for switching to the guest
> > > > context, and one for switching to the host context, and we get the
> > > > benefit of only having to evaluate the dirty flag once on each path,
> > > > plus we give the compiler some more room to inline some of this
> > > > functionality.
> > > >
> > > > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > > > ---
> > > > arch/arm64/include/asm/kvm_hyp.h | 10 ++-----
> > > > arch/arm64/kvm/hyp/debug-sr.c | 56 +++++++++++++++++++++++++++-------------
> > > > arch/arm64/kvm/hyp/switch.c | 6 ++---
> > > > 3 files changed, 42 insertions(+), 30 deletions(-)
> > > >
> > > > diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> > > > index 08d3bb6..a0e5a70 100644
> > > > --- a/arch/arm64/include/asm/kvm_hyp.h
> > > > +++ b/arch/arm64/include/asm/kvm_hyp.h
> > > > @@ -139,14 +139,8 @@ void __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt);
> > > > void __sysreg32_save_state(struct kvm_vcpu *vcpu);
> > > > void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
> > > >
> > > > -void __debug_save_state(struct kvm_vcpu *vcpu,
> > > > - struct kvm_guest_debug_arch *dbg,
> > > > - struct kvm_cpu_context *ctxt);
> > > > -void __debug_restore_state(struct kvm_vcpu *vcpu,
> > > > - struct kvm_guest_debug_arch *dbg,
> > > > - struct kvm_cpu_context *ctxt);
> > > > -void __debug_cond_save_host_state(struct kvm_vcpu *vcpu);
> > > > -void __debug_cond_restore_host_state(struct kvm_vcpu *vcpu);
> > > > +void __debug_switch_to_guest(struct kvm_vcpu *vcpu);
> > > > +void __debug_switch_to_host(struct kvm_vcpu *vcpu);
> > > >
> > > > void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
> > > > void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
> > > > diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
> > > > index a2291b6..b4cd8e0 100644
> > > > --- a/arch/arm64/kvm/hyp/debug-sr.c
> > > > +++ b/arch/arm64/kvm/hyp/debug-sr.c
> > > > @@ -116,16 +116,13 @@ static void __hyp_text __debug_restore_spe(u64 pmscr_el1)
> > > > write_sysreg_s(pmscr_el1, PMSCR_EL1);
> > > > }
> > > >
> > > > -void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
> > > > - struct kvm_guest_debug_arch *dbg,
> > > > - struct kvm_cpu_context *ctxt)
> > > > +static void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
> > > > + struct kvm_guest_debug_arch *dbg,
> > > > + struct kvm_cpu_context *ctxt)
> > > > {
> > > > u64 aa64dfr0;
> > > > int brps, wrps;
> > > >
> > > > - if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
> > > > - return;
> > > > -
> > > > aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
> > > > brps = (aa64dfr0 >> 12) & 0xf;
> > > > wrps = (aa64dfr0 >> 20) & 0xf;
> > > > @@ -138,16 +135,13 @@ void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
> > > > ctxt->sys_regs[MDCCINT_EL1] = read_sysreg(mdccint_el1);
> > > > }
> > > >
> > > > -void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
> > > > - struct kvm_guest_debug_arch *dbg,
> > > > - struct kvm_cpu_context *ctxt)
> > > > +static void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
> > > > + struct kvm_guest_debug_arch *dbg,
> > > > + struct kvm_cpu_context *ctxt)
> > > > {
> > > > u64 aa64dfr0;
> > > > int brps, wrps;
> > > >
> > > > - if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
> > > > - return;
> > > > -
> > > > aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
> > > >
> > > > brps = (aa64dfr0 >> 12) & 0xf;
> > > > @@ -161,24 +155,50 @@ void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
> > > > write_sysreg(ctxt->sys_regs[MDCCINT_EL1], mdccint_el1);
> > > > }
> > > >
> > > > -void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
> > > > +void __hyp_text __debug_switch_to_guest(struct kvm_vcpu *vcpu)
> > > > {
> > > > - __debug_save_state(vcpu, &vcpu->arch.host_debug_state.regs,
> > > > - kern_hyp_va(vcpu->arch.host_cpu_context));
> > > > + struct kvm_cpu_context *__host_ctxt;
> > > > + struct kvm_cpu_context *__guest_ctxt;
> > > > + struct kvm_guest_debug_arch *__host_dbg;
> > > > + struct kvm_guest_debug_arch *__guest_dbg;
> > >
> > > I caught in your reply to Marc that the __ prefix here is for hyp mode
> > > accessible code and data, but do we also need to use it for stack data?
> > > No big deal, but it's not very pretty.
> > >
> >
> > sure.
> >
> > > >
> > > > /* Non-VHE: Disable and flush SPE data generation
> > > > * VHE: The vcpu can run. but it can't hide. */
> > > > if (!has_vhe())
> > > > __debug_save_spe_nvhe(&vcpu->arch.host_debug_state.pmscr_el1);
> > > > +
> > > > + if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
> > > > + return;
> > > > +
> > > > + __host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
> > > > + __guest_ctxt = &vcpu->arch.ctxt;
> > > > + __host_dbg = &vcpu->arch.host_debug_state.regs;
> > > > + __guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr);
> > > > +
> > > > + __debug_save_state(vcpu, __host_dbg, __host_ctxt);
> > > > + __debug_restore_state(vcpu, __guest_dbg, __guest_ctxt);
> > > > }
> > > >
> > > > -void __hyp_text __debug_cond_restore_host_state(struct kvm_vcpu *vcpu)
> > > > +void __hyp_text __debug_switch_to_host(struct kvm_vcpu *vcpu)
> > > > {
> > > > + struct kvm_cpu_context *__host_ctxt;
> > > > + struct kvm_cpu_context *__guest_ctxt;
> > > > + struct kvm_guest_debug_arch *__host_dbg;
> > > > + struct kvm_guest_debug_arch *__guest_dbg;
> > > > +
> > > > if (!has_vhe())
> > > > __debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
> > > >
> > > > - __debug_restore_state(vcpu, &vcpu->arch.host_debug_state.regs,
> > > > - kern_hyp_va(vcpu->arch.host_cpu_context));
> > > > + if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
> > > > + return;
> > > > +
> > > > + __host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
> > > > + __guest_ctxt = &vcpu->arch.ctxt;
> > > > + __host_dbg = &vcpu->arch.host_debug_state.regs;
> > > > + __guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr);
> > > > +
> > > > + __debug_save_state(vcpu, __guest_dbg, __guest_ctxt);
> > > > + __debug_restore_state(vcpu, __host_dbg, __host_ctxt);
> > > >
> > > > vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
> > > > }
> > > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > > > index ef05c59..e270cba 100644
> > > > --- a/arch/arm64/kvm/hyp/switch.c
> > > > +++ b/arch/arm64/kvm/hyp/switch.c
> > > > @@ -271,7 +271,6 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
> > > > guest_ctxt = &vcpu->arch.ctxt;
> > > >
> > > > __sysreg_save_host_state(host_ctxt);
> > > > - __debug_cond_save_host_state(vcpu);
> > > >
> > > > __activate_traps(vcpu);
> > > > __activate_vm(vcpu);
> > > > @@ -285,7 +284,7 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
> > > > */
> > > > __sysreg32_restore_state(vcpu);
> > > > __sysreg_restore_guest_state(guest_ctxt);
> > > > - __debug_restore_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
> > > > + __debug_switch_to_guest(vcpu);
> > > >
> > > > /* Jump in the fire! */
> > > > again:
> > > > @@ -353,12 +352,11 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
> > > >
> > > > __sysreg_restore_host_state(host_ctxt);
> > > >
> > > > - __debug_save_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
> > > > /*
> > > > * This must come after restoring the host sysregs, since a non-VHE
> > > > * system may enable SPE here and make use of the TTBRs.
> > > > */
> > > > - __debug_cond_restore_host_state(vcpu);
> > > > + __debug_switch_to_host(vcpu);
> > > >
> > > > return exit_code;
> > > > }
> > > > --
> > > > 2.9.0
> > > >
> > >
> > > This looks like a nice cleanup, but can you please add a note to the
> > > commit message about why we don't need to use the
> > >
> > > save-host-state
> > > activate-traps-and-vm
> > > restore-guest-state
> > >
> > > and the reverse, patterns for the debug registers?
> >
> > I think the current commit message motivates the change fine.
> >
>
> The motivation is obvious, the justification for an additional change
> is not. How does it justify changing the sequence
>
> save-debug-host-state
> activate-debug-traps /* and other stuff in between */
> restore-debug-guest-state
>
> to
>
> activate-debug-traps /* and other stuff in between */
> save-debug-host-state
> restore-debug-guest-state
>
It doesn't, and I don't think it has to. The code is there, and I can't
argue all possible interdependencies between all code lines in English
and explain why it's safe, that requires looking at the code. The
commit message should motivate the change, not explain code which
requires understanding the software and the architecture.
If there was a clear rule that we do 'save, activate, restore' for
everything, it would make sense to explain why we can break that, but
that is not how I see the implementation. For example, there is no
particular reason why we restore the vgic before the timer, or the vgic
after we activate the stage 2 translation. The key here is
understanding the flexibility the architecture gives you.
You can then argue that since this bothers you, I should just add
something in the commit message, but I think that can be just as
misleading, because it would imply a total order, which doesn't exist.
Also, since you clearly understood the flow and what is going on, we're
probably fine as it is.
Thanks,
-Christoffer
^ permalink raw reply
* [PATCH 9/9] arm64: dts: allwinner: a64: Enable sound on Pine64 and SoPine
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com>
This commit enables I2S, digital and analog parts of audiocodec on
Pine64 and SoPine boards.
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts | 16 ++++++++++++++++
.../boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts | 16 ++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
index 806442d3e846..369d9b749521 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
@@ -64,6 +64,18 @@
};
};
+&codec {
+ status = "okay";
+};
+
+&codec_analog {
+ status = "okay";
+};
+
+&dai {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -229,6 +241,10 @@
regulator-name = "vcc-rtc";
};
+&sound {
+ status = "okay";
+};
+
/* On Exp and Euler connectors */
&uart0 {
pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts
index 0eb2acedf8c3..9de5ddcc3656 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts
@@ -69,6 +69,18 @@
};
};
+&codec {
+ status = "okay";
+};
+
+&codec_analog {
+ status = "okay";
+};
+
+&dai {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -133,6 +145,10 @@
regulator-name = "vcc-wifi";
};
+&sound {
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;
--
2.15.0
^ permalink raw reply related
* [PATCH 8/9] arm64: dts: allwinner: a64: Add nodes necessary for analog sound support
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com>
Add nodes for i2s, digital and analog parts of audiocodec on A64
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 52 +++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index d783d164b9c3..504f16e3d92d 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -112,6 +112,28 @@
method = "smc";
};
+ sound: sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "SUN50i Audio Card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,frame-master = <&cpudai>;
+ simple-audio-card,bitclock-master = <&cpudai>;
+ simple-audio-card,mclk-fs = <512>;
+ simple-audio-card,aux-devs = <&codec_analog>;
+ simple-audio-card,routing =
+ "Left DAC", "AIF1 Slot 0 Left",
+ "Right DAC", "AIF1 Slot 0 Right";
+ status = "disabled";
+
+ cpudai: simple-audio-card,cpu {
+ sound-dai = <&dai>;
+ };
+
+ link_codec: simple-audio-card,codec {
+ sound-dai = <&codec>;
+ };
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13
@@ -382,6 +404,30 @@
};
};
+ dai: dai@1c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun50i-a64-acodec-i2s";
+ reg = <0x01c22c00 0x200>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "apb", "mod";
+ resets = <&ccu RST_BUS_CODEC>;
+ reset-names = "rst";
+ dmas = <&dma 15>, <&dma 15>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ codec: codec at 1c22e00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun50i-a64-codec";
+ reg = <0x01c22e00 0x600>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "bus", "mod";
+ status = "disabled";
+ };
+
uart0: serial at 1c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
@@ -563,6 +609,12 @@
#reset-cells = <1>;
};
+ codec_analog: codec-analog at 1f015c0 {
+ compatible = "allwinner,sun50i-a64-codec-analog";
+ reg = <0x01f015c0 0x4>;
+ status = "disabled";
+ };
+
r_pio: pinctrl at 1f02c00 {
compatible = "allwinner,sun50i-a64-r-pinctrl";
reg = <0x01f02c00 0x400>;
--
2.15.0
^ permalink raw reply related
* [PATCH 7/9] ASoC: sun8i-codec-analog: Add support for A64 SoC
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com>
From: Marcus Cooper <codekipper@gmail.com>
Analog part of audiocodec is very similar to other codecs supports by
this driver, but has different registers
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
.../bindings/sound/sun8i-codec-analog.txt | 1 +
sound/soc/sunxi/Kconfig | 2 +-
sound/soc/sunxi/sun8i-codec-analog.c | 227 +++++++++++++++++++++
3 files changed, 229 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
index 07356758bd91..f38896850e4d 100644
--- a/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
+++ b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
@@ -5,6 +5,7 @@ Required properties:
- "allwinner,sun8i-a23-codec-analog"
- "allwinner,sun8i-h3-codec-analog"
- "allwinner,sun8i-v3s-codec-analog"
+ - "allwinner,sun50i-a64-codec-analog"
Required properties if not a sub-node of the PRCM node:
- reg: must contain the registers location and length
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 22408bc2d6ec..26072b74e47f 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -12,7 +12,7 @@ config SND_SUN4I_CODEC
config SND_SUN8I_CODEC
tristate "Allwinner SUN8I audio codec"
depends on OF
- depends on MACH_SUN8I || COMPILE_TEST
+ depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
select REGMAP_MMIO
help
This option enables the digital part of the internal audio codec for
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
index 4e39d2668286..adb7fe087c73 100644
--- a/sound/soc/sunxi/sun8i-codec-analog.c
+++ b/sound/soc/sunxi/sun8i-codec-analog.c
@@ -30,6 +30,7 @@
/* Codec analog control register offsets and bit fields */
#define SUN8I_ADDA_HP_VOLC 0x00
#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7
+#define SUN50I_ADDA_HP_VOLC_HPPAEN 6
#define SUN8I_ADDA_HP_VOLC_HP_VOL 0
#define SUN8I_ADDA_LOMIXSC 0x01
#define SUN8I_ADDA_LOMIXSC_MIC1 6
@@ -48,6 +49,7 @@
#define SUN8I_ADDA_ROMIXSC_DACR 1
#define SUN8I_ADDA_ROMIXSC_DACL 0
#define SUN8I_ADDA_DAC_PA_SRC 0x03
+#define SUN50I_ADDA_DAC_PA_SRC 0x0a
#define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7
#define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6
#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5
@@ -62,9 +64,16 @@
#define SUN8I_ADDA_LINEIN_GCTRL 0x05
#define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4
#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0
+#define SUN50I_ADDA_LINEOUT_CTRL0 0x05
+#define SUN50I_ADDA_LINEOUT_CTRL0_LEN 7
+#define SUN50I_ADDA_LINEOUT_CTRL0_REN 6
+#define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL 5
+#define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL 4
#define SUN8I_ADDA_MICIN_GCTRL 0x06
#define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4
#define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0
+#define SUN50I_ADDA_LINEOUT_CTRL1 0x06
+#define SUN50I_ADDA_LINEOUT_CTRL1_VOL 0
#define SUN8I_ADDA_PAEN_HP_CTRL 0x07
#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7
#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */
@@ -364,6 +373,61 @@ static const struct snd_soc_dapm_widget sun8i_v3s_codec_mixer_widgets[] = {
ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)),
};
+static const struct snd_soc_dapm_widget sun50i_codec_common_widgets[] = {
+ /* ADC */
+ SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
+ SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0),
+ SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
+ SUN8I_ADDA_ADC_AP_EN_ADCREN, 0),
+
+ /* DAC */
+ SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_DAC_PA_SRC,
+ SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0),
+ SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_DAC_PA_SRC,
+ SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0),
+ /*
+ * Due to this component and the codec belonging to separate DAPM
+ * contexts, we need to manually link the above widgets to their
+ * stream widgets at the card level.
+ */
+
+ /* Line In */
+ SND_SOC_DAPM_INPUT("LINEIN"),
+
+ /* Microphone inputs */
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+
+ /* Microphone Bias */
+ SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
+ SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN,
+ 0, NULL, 0),
+
+ /* Mic input path */
+ SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
+ SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL,
+ SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0),
+
+ /* Mixers */
+ SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_DAC_PA_SRC,
+ SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
+ sun8i_codec_mixer_controls,
+ ARRAY_SIZE(sun8i_codec_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_DAC_PA_SRC,
+ SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0,
+ sun8i_codec_mixer_controls,
+ ARRAY_SIZE(sun8i_codec_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
+ SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0,
+ sun8i_codec_adc_mixer_controls,
+ ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
+ SUN8I_ADDA_ADC_AP_EN_ADCREN, 0,
+ sun8i_codec_adc_mixer_controls,
+ ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
+};
+
static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = {
/* Microphone Routes */
{ "Mic1 Amplifier", NULL, "MIC1"},
@@ -408,6 +472,17 @@ static const struct snd_kcontrol_new sun8i_a23_codec_hp_ctrls[] = {
SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0),
};
+static const struct snd_kcontrol_new sun50i_a64_codec_hp_ctrls[] = {
+ SOC_SINGLE_TLV("Headphone Playback Volume",
+ SUN8I_ADDA_HP_VOLC,
+ SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
+ sun8i_codec_hp_vol_scale),
+ SOC_DOUBLE("Headphone Playback Switch",
+ SUN50I_ADDA_DAC_PA_SRC,
+ SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE,
+ SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0),
+};
+
static const char * const sun8i_codec_hp_src_enum_text[] = {
"DAC", "Mixer",
};
@@ -461,6 +536,14 @@ static const struct snd_soc_dapm_widget sun8i_a23_codec_hp_widgets[] = {
SND_SOC_DAPM_OUTPUT("HP"),
};
+static const struct snd_soc_dapm_widget sun50i_a64_codec_hp_widgets[] = {
+ SND_SOC_DAPM_MUX("Headphone Source Playback Route",
+ SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
+ SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_HP_VOLC,
+ SUN50I_ADDA_HP_VOLC_HPPAEN, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("HP"),
+};
+
static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = {
{ "Headphone Source Playback Route", "DAC", "Left DAC" },
{ "Headphone Source Playback Route", "DAC", "Right DAC" },
@@ -471,6 +554,15 @@ static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = {
{ "HP", NULL, "Headphone Amp" },
};
+static const struct snd_soc_dapm_route sun50i_codec_headphone_routes[] = {
+ { "Headphone Source Playback Route", "DAC", "Left DAC" },
+ { "Headphone Source Playback Route", "DAC", "Right DAC" },
+ { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
+ { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
+ { "Headphone Amp", NULL, "Headphone Source Playback Route" },
+ { "HP", NULL, "Headphone Amp" },
+};
+
static int sun8i_a23_codec_add_headphone(struct snd_soc_component *cmpnt)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
@@ -525,6 +617,41 @@ static int sun8i_codec_add_mbias(struct snd_soc_component *cmpnt)
return ret;
}
+static int sun50i_a64_codec_add_headphone(struct snd_soc_component *cmpnt)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
+ struct device *dev = cmpnt->dev;
+ int ret;
+
+ ret = snd_soc_add_component_controls(cmpnt,
+ sun50i_a64_codec_hp_ctrls,
+ ARRAY_SIZE(
+ sun50i_a64_codec_hp_ctrls));
+ if (ret) {
+ dev_err(dev, "Failed to add Headphone controls: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_new_controls(dapm,
+ sun50i_a64_codec_hp_widgets,
+ ARRAY_SIZE(
+ sun50i_a64_codec_hp_widgets));
+ if (ret) {
+ dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, sun50i_codec_headphone_routes,
+ ARRAY_SIZE(
+ sun50i_codec_headphone_routes));
+ if (ret) {
+ dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/* hmic specific widget */
static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = {
SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
@@ -618,6 +745,17 @@ static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = {
SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0),
};
+static const struct snd_kcontrol_new sun50i_codec_lineout_ctrls[] = {
+ SOC_SINGLE_TLV("Line Out Playback Volume",
+ SUN50I_ADDA_LINEOUT_CTRL1,
+ SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0,
+ sun8i_codec_lineout_vol_scale),
+ SOC_DOUBLE("Line Out Playback Switch",
+ SUN50I_ADDA_LINEOUT_CTRL0,
+ SUN50I_ADDA_LINEOUT_CTRL0_REN,
+ SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0),
+};
+
static const char * const sun8i_codec_lineout_src_enum_text[] = {
"Stereo", "Mono Differential",
};
@@ -628,11 +766,22 @@ static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum,
SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC,
sun8i_codec_lineout_src_enum_text);
+static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum,
+ SUN50I_ADDA_LINEOUT_CTRL0,
+ SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL,
+ SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL,
+ sun8i_codec_lineout_src_enum_text);
+
static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = {
SOC_DAPM_ENUM("Line Out Source Playback Route",
sun8i_codec_lineout_src_enum),
};
+static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = {
+ SOC_DAPM_ENUM("Line Out Source Playback Route",
+ sun50i_codec_lineout_src_enum),
+};
+
static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = {
SND_SOC_DAPM_MUX("Line Out Source Playback Route",
SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src),
@@ -642,6 +791,17 @@ static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = {
SND_SOC_DAPM_OUTPUT("LINEOUT"),
};
+static const struct snd_soc_dapm_widget sun50i_codec_lineout_widgets[] = {
+ SND_SOC_DAPM_MUX("Line Out Source Playback Route",
+ SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
+ /* It is unclear if this is a buffer or gate, model it as a supply */
+ SND_SOC_DAPM_SUPPLY("Left Line Out Enable", SUN50I_ADDA_LINEOUT_CTRL0,
+ SUN50I_ADDA_LINEOUT_CTRL0_LEN, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Right Line Out Enable", SUN50I_ADDA_LINEOUT_CTRL0,
+ SUN50I_ADDA_LINEOUT_CTRL0_REN, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("LINEOUT"),
+};
+
static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = {
{ "Line Out Source Playback Route", "Stereo", "Left Mixer" },
{ "Line Out Source Playback Route", "Stereo", "Right Mixer" },
@@ -651,6 +811,17 @@ static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = {
{ "LINEOUT", NULL, "Line Out Enable", },
};
+static const struct snd_soc_dapm_route sun50i_codec_lineout_routes[] = {
+ { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
+ { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
+ { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
+ { "Line Out Source Playback Route", "Mono Differential",
+ "Right Mixer" },
+ { "LINEOUT", NULL, "Line Out Source Playback Route" },
+ { "LINEOUT", NULL, "Left Line Out Enable", },
+ { "LINEOUT", NULL, "Right Line Out Enable", },
+};
+
static int sun8i_h3_codec_add_lineout(struct snd_soc_component *cmpnt)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
@@ -747,6 +918,39 @@ static int sun8i_codec_add_mic2(struct snd_soc_component *cmpnt)
return 0;
}
+static int sun50i_a64_codec_add_lineout(struct snd_soc_component *cmpnt)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
+ struct device *dev = cmpnt->dev;
+ int ret;
+
+ ret = snd_soc_add_component_controls(cmpnt,
+ sun50i_codec_lineout_ctrls,
+ ARRAY_SIZE(
+ sun50i_codec_lineout_ctrls));
+ if (ret) {
+ dev_err(dev, "Failed to add Line Out controls: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_new_controls(dapm, sun50i_codec_lineout_widgets,
+ ARRAY_SIZE(
+ sun50i_codec_lineout_widgets));
+ if (ret) {
+ dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, sun50i_codec_lineout_routes,
+ ARRAY_SIZE(sun50i_codec_lineout_routes));
+ if (ret) {
+ dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
struct sun8i_codec_analog_quirks {
bool has_headphone;
bool has_hmic;
@@ -868,6 +1072,16 @@ static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = {
.probe = sun8i_codec_analog_cmpnt_probe,
};
+static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
+ .controls = sun8i_codec_common_controls,
+ .num_controls = ARRAY_SIZE(sun8i_codec_common_controls),
+ .dapm_widgets = sun50i_codec_common_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun50i_codec_common_widgets),
+ .dapm_routes = sun8i_codec_common_routes,
+ .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes),
+ .probe = sun8i_codec_analog_cmpnt_probe,
+};
+
static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
.has_headphone = true,
.has_hmic = true,
@@ -893,6 +1107,15 @@ static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = {
.cmpnt_drv = &sun8i_codec_analog_cmpnt_drv,
};
+static const struct sun8i_codec_analog_quirks sun50i_a64_quirks = {
+ .has_headphone = true,
+ .has_hmic = false,
+ .has_lineout = true,
+ .add_headphone = sun50i_a64_codec_add_headphone,
+ .add_lineout = sun50i_a64_codec_add_lineout,
+ .cmpnt_drv = &sun50i_codec_analog_cmpnt_drv,
+};
+
static const struct of_device_id sun8i_codec_analog_of_match[] = {
{
.compatible = "allwinner,sun8i-a23-codec-analog",
@@ -906,6 +1129,10 @@ static const struct of_device_id sun8i_codec_analog_of_match[] = {
.compatible = "allwinner,sun8i-v3s-codec-analog",
.data = &sun8i_v3s_quirks,
},
+ {
+ .compatible = "allwinner,sun50i-a64-codec-analog",
+ .data = &sun50i_a64_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
--
2.15.0
^ permalink raw reply related
* [PATCH 6/9] ASoC: sun8i-codec-analog: Add component driver field to quirks structure
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com>
This is necessary for upcoming addition of A64 support. A64 uses
the same DAPM routes, but slightly different widgets. Use approach from
sun4i-codec driver and pass appropriate component driver through quirks.
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
sound/soc/sunxi/sun8i-codec-analog.c | 57 +++++++++++++++++++++---------------
1 file changed, 33 insertions(+), 24 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
index 384f582b6f69..4e39d2668286 100644
--- a/sound/soc/sunxi/sun8i-codec-analog.c
+++ b/sound/soc/sunxi/sun8i-codec-analog.c
@@ -759,24 +759,6 @@ struct sun8i_codec_analog_quirks {
int (*add_lineout)(struct snd_soc_component *cmpnt);
};
-static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
- .has_headphone = true,
- .has_hmic = true,
- .has_linein = true,
- .has_mbias = true,
- .has_mic2 = true,
- .add_headphone = sun8i_a23_codec_add_headphone,
-};
-
-static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
- .has_linein = true,
- .has_lineout = true,
- .has_mbias = true,
- .has_mic2 = true,
- .add_lineout = sun8i_h3_codec_add_lineout,
-};
-
-
static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt,
const struct sun8i_codec_analog_quirks *quirks)
{
@@ -819,11 +801,6 @@ static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt,
return 0;
}
-static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = {
- .has_headphone = true,
- .has_hmic = true,
-};
-
static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
{
struct device *dev = cmpnt->dev;
@@ -891,6 +868,31 @@ static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = {
.probe = sun8i_codec_analog_cmpnt_probe,
};
+static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
+ .has_headphone = true,
+ .has_hmic = true,
+ .has_linein = true,
+ .has_mbias = true,
+ .has_mic2 = true,
+ .add_headphone = sun8i_a23_codec_add_headphone,
+ .cmpnt_drv = &sun8i_codec_analog_cmpnt_drv,
+};
+
+static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
+ .has_linein = true,
+ .has_lineout = true,
+ .has_mbias = true,
+ .has_mic2 = true,
+ .add_lineout = sun8i_h3_codec_add_lineout,
+ .cmpnt_drv = &sun8i_codec_analog_cmpnt_drv,
+};
+
+static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = {
+ .has_headphone = true,
+ .has_hmic = true,
+ .cmpnt_drv = &sun8i_codec_analog_cmpnt_drv,
+};
+
static const struct of_device_id sun8i_codec_analog_of_match[] = {
{
.compatible = "allwinner,sun8i-a23-codec-analog",
@@ -913,6 +915,13 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev)
struct resource *res;
struct regmap *regmap;
void __iomem *base;
+ const struct sun8i_codec_analog_quirks *quirks;
+
+ quirks = of_device_get_match_data(&pdev->dev);
+ if (quirks == NULL) {
+ dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
+ return -ENODEV;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
@@ -928,7 +937,7 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev)
}
return devm_snd_soc_register_component(&pdev->dev,
- &sun8i_codec_analog_cmpnt_drv,
+ quirks->cmpnt_drv,
NULL, 0);
}
--
2.15.0
^ permalink raw reply related
* [PATCH 5/9] ASoC: sun8i-codec-analog: Use callbacks to add headphones and lineout outputs
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com>
From: Marcus Cooper <codekipper@gmail.com>
Widgets for headphones and lineout outputs on A64 are different enough
and use different regs, so move addition of these outputs into callback to
simplify upcoming A64 support.
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
---
sound/soc/sunxi/sun8i-codec-analog.c | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
index 485e79f292c4..384f582b6f69 100644
--- a/sound/soc/sunxi/sun8i-codec-analog.c
+++ b/sound/soc/sunxi/sun8i-codec-analog.c
@@ -397,7 +397,7 @@ static const struct snd_soc_dapm_route sun8i_codec_mixer_routes[] = {
/* headphone specific controls, widgets, and routes */
static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1);
-static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = {
+static const struct snd_kcontrol_new sun8i_a23_codec_hp_ctrls[] = {
SOC_SINGLE_TLV("Headphone Playback Volume",
SUN8I_ADDA_HP_VOLC,
SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
@@ -447,7 +447,7 @@ static int sun8i_headphone_amp_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = {
+static const struct snd_soc_dapm_widget sun8i_a23_codec_hp_widgets[] = {
SND_SOC_DAPM_MUX("Headphone Source Playback Route",
SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
SND_SOC_DAPM_OUT_DRV_E("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
@@ -471,22 +471,24 @@ static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = {
{ "HP", NULL, "Headphone Amp" },
};
-static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt)
+static int sun8i_a23_codec_add_headphone(struct snd_soc_component *cmpnt)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
struct device *dev = cmpnt->dev;
int ret;
ret = snd_soc_add_component_controls(cmpnt,
- sun8i_codec_headphone_controls,
- ARRAY_SIZE(sun8i_codec_headphone_controls));
+ sun8i_a23_codec_hp_ctrls,
+ ARRAY_SIZE(
+ sun8i_a23_codec_hp_ctrls));
if (ret) {
dev_err(dev, "Failed to add Headphone controls: %d\n", ret);
return ret;
}
- ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets,
- ARRAY_SIZE(sun8i_codec_headphone_widgets));
+ ret = snd_soc_dapm_new_controls(dapm,
+ sun8i_a23_codec_hp_widgets,
+ ARRAY_SIZE(sun8i_a23_codec_hp_widgets));
if (ret) {
dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret);
return ret;
@@ -604,6 +606,7 @@ static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale,
0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
);
+
static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = {
SOC_SINGLE_TLV("Line Out Playback Volume",
SUN8I_ADDA_PHONE_GAIN_CTRL,
@@ -648,7 +651,7 @@ static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = {
{ "LINEOUT", NULL, "Line Out Enable", },
};
-static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt)
+static int sun8i_h3_codec_add_lineout(struct snd_soc_component *cmpnt)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
struct device *dev = cmpnt->dev;
@@ -751,6 +754,9 @@ struct sun8i_codec_analog_quirks {
bool has_lineout;
bool has_mbias;
bool has_mic2;
+ const struct snd_soc_component_driver *cmpnt_drv;
+ int (*add_headphone)(struct snd_soc_component *cmpnt);
+ int (*add_lineout)(struct snd_soc_component *cmpnt);
};
static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
@@ -759,6 +765,7 @@ static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
.has_linein = true,
.has_mbias = true,
.has_mic2 = true,
+ .add_headphone = sun8i_a23_codec_add_headphone,
};
static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
@@ -766,8 +773,10 @@ static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
.has_lineout = true,
.has_mbias = true,
.has_mic2 = true,
+ .add_lineout = sun8i_h3_codec_add_lineout,
};
+
static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt,
const struct sun8i_codec_analog_quirks *quirks)
{
@@ -834,7 +843,7 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
return ret;
if (quirks->has_headphone) {
- ret = sun8i_codec_add_headphone(cmpnt);
+ ret = quirks->add_headphone(cmpnt);
if (ret)
return ret;
}
@@ -852,7 +861,7 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
}
if (quirks->has_lineout) {
- ret = sun8i_codec_add_lineout(cmpnt);
+ ret = quirks->add_lineout(cmpnt);
if (ret)
return ret;
}
--
2.15.0
^ permalink raw reply related
* [PATCH 4/9] ASoC: sun8i-codec: Add support for A64 SoC
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com>
Digital part of audio codec block in the A64 is very similar to what
is used by the A33(sun8i) devices. However, it uses different LRCK
divider.
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
.../bindings/sound/{sun8i-a33-codec.txt => sun8i-codec.txt} | 6 ++++--
sound/soc/sunxi/sun8i-codec.c | 9 +++++++++
2 files changed, 13 insertions(+), 2 deletions(-)
rename Documentation/devicetree/bindings/sound/{sun8i-a33-codec.txt => sun8i-codec.txt} (91%)
diff --git a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt b/Documentation/devicetree/bindings/sound/sun8i-codec.txt
similarity index 91%
rename from Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt
rename to Documentation/devicetree/bindings/sound/sun8i-codec.txt
index 2ca3d138528e..ffcf9079a67c 100644
--- a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun8i-codec.txt
@@ -1,7 +1,7 @@
Allwinner SUN8I audio codec
------------------------------------
-On Sun8i-A33 SoCs, the audio is separated in different parts:
+On Sun8i-A33 and Sun50i-A64 SoCs, the audio is separated in different parts:
- A DAI driver. It uses the "sun4i-i2s" driver which is
documented here:
Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -16,7 +16,9 @@ On Sun8i-A33 SoCs, the audio is separated in different parts:
This bindings documentation exposes Sun8i codec (digital part).
Required properties:
-- compatible: must be "allwinner,sun8i-a33-codec"
+- compatible: should be one of the following:
+ - "allwinner,sun8i-a33-codec"
+ - "allwinner,sun50i-a64-codec"
- reg: must contain the registers location and length
- interrupts: must contain the codec interrupt
- clocks: a list of phandle + clock-specifer pairs, one for each entry
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 054201d1de03..0e2a5adcfb96 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -52,6 +52,7 @@
#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9
#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6
#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16 (1 << 6)
+#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_64 (2 << 6)
#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4
#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4)
#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2
@@ -456,6 +457,10 @@ static const struct sun8i_codec_quirks sun8i_a33_codec_quirks = {
.aif1_lrck_div = SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16,
};
+static const struct sun8i_codec_quirks sun50i_a64_codec_quirks = {
+ .aif1_lrck_div = SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_64,
+};
+
static int sun8i_codec_probe(struct platform_device *pdev)
{
struct resource *res_base;
@@ -551,6 +556,10 @@ static const struct of_device_id sun8i_codec_of_match[] = {
.compatible = "allwinner,sun8i-a33-codec",
.data = &sun8i_a33_codec_quirks,
},
+ {
+ .compatible = "allwinner,sun50i-a64-codec",
+ .data = &sun50i_a64_codec_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
--
2.15.0
^ permalink raw reply related
* [PATCH 3/9] ASoC: sun8i-codec: Add quirk to specify aif1_lrck_div value
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com>
LRCK divider for A64 differs from A33, so add a quirk to support that.
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
sound/soc/sunxi/sun8i-codec.c | 38 ++++++++++++++++++++++++++++++++------
1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 3dd183be08a4..054201d1de03 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/of_device.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -75,11 +76,22 @@
#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6)
#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9)
+/*
+ * struct sun8i_codec_quirks - Differences between SoC variants.
+ *
+ * @aif1_lrck_div: LRCK divider
+ */
+struct sun8i_codec_quirks {
+ unsigned int aif1_lrck_div;
+};
+
+
struct sun8i_codec {
- struct device *dev;
- struct regmap *regmap;
- struct clk *clk_module;
- struct clk *clk_bus;
+ struct device *dev;
+ struct regmap *regmap;
+ struct clk *clk_module;
+ struct clk *clk_bus;
+ const struct sun8i_codec_quirks *variant;
};
static int sun8i_codec_runtime_resume(struct device *dev)
@@ -305,7 +317,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
- SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
+ scodec->variant->aif1_lrck_div);
sample_rate = sun8i_codec_get_hw_rate(params);
if (sample_rate < 0)
@@ -440,6 +452,10 @@ static const struct regmap_config sun8i_codec_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
+static const struct sun8i_codec_quirks sun8i_a33_codec_quirks = {
+ .aif1_lrck_div = SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16,
+};
+
static int sun8i_codec_probe(struct platform_device *pdev)
{
struct resource *res_base;
@@ -453,6 +469,13 @@ static int sun8i_codec_probe(struct platform_device *pdev)
scodec->dev = &pdev->dev;
+ scodec->variant = of_device_get_match_data(&pdev->dev);
+ if (!scodec->variant) {
+ dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
+ return -ENODEV;
+ }
+
+
scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
if (IS_ERR(scodec->clk_module)) {
dev_err(&pdev->dev, "Failed to get the module clock\n");
@@ -524,7 +547,10 @@ static int sun8i_codec_remove(struct platform_device *pdev)
}
static const struct of_device_id sun8i_codec_of_match[] = {
- { .compatible = "allwinner,sun8i-a33-codec" },
+ {
+ .compatible = "allwinner,sun8i-a33-codec",
+ .data = &sun8i_a33_codec_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
--
2.15.0
^ permalink raw reply related
* [PATCH 2/9] ASoC: sun4i-i2s: Add compatibility with A64 codec I2S
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com>
From: Marcus Cooper <codekipper@gmail.com>
The I2S block used for the audio codec in the A64 is very similar
to what is used by the A10(sun4i) devices. However, its TX FIFO is
located at a different address.
[vasilykh: - added fixed_wss and wss_value to A64 quirks,
- changed compatible to 'allwinner,sun50i-a64-acodec-i2s,
since A64 has 3 more I2S blocks that are not compatible
with audio codec I2S]
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
.../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++
sound/soc/sunxi/sun4i-i2s.c | 23 ++++++++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index 05d7135a8d2f..ab86f266962a 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -9,6 +9,7 @@ Required properties:
- "allwinner,sun4i-a10-i2s"
- "allwinner,sun6i-a31-i2s"
- "allwinner,sun8i-h3-i2s"
+ - "allwinner,sun50i-a64-acodec-i2s"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: should contain the I2S interrupt.
@@ -24,6 +25,7 @@ Required properties:
Required properties for the following compatibles:
- "allwinner,sun6i-a31-i2s"
- "allwinner,sun8i-h3-i2s"
+ - "allwinner,sun50i-a64-acodec-i2s"
- resets: phandle to the reset line for this codec
Example:
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 54c16eb64713..2c060e015725 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -942,6 +942,25 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2),
};
+static const struct sun4i_i2s_quirks sun50i_a64_acodec_i2s_quirks = {
+ .has_reset = true,
+ .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
+ .sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
+ .has_slave_select_bit = true,
+ .fixed_wss = true,
+ .wss_value = 3,
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
+ .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+ .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
+ .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
+ .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+ .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+ .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+ .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
+ .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+};
+
static int sun4i_i2s_init_regmap_fields(struct device *dev,
struct sun4i_i2s *i2s)
{
@@ -1146,6 +1165,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
.compatible = "allwinner,sun8i-h3-i2s",
.data = &sun8i_h3_i2s_quirks,
},
+ {
+ .compatible = "allwinner,sun50i-a64-acodec-i2s",
+ .data = &sun50i_a64_acodec_i2s_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
--
2.15.0
^ permalink raw reply related
* [PATCH 1/9] ASoC: sun4i-i2s: Add quirk to handle fixed WSS
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com>
I2S for audio codec on sun50i-A64 always uses fixed word select size value,
no matter what is sample width. Add quirk to support that.
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 04f92583a969..54c16eb64713 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -132,6 +132,8 @@
* @mclk_offset: Value by which mclkdiv needs to be adjusted.
* @bclk_offset: Value by which bclkdiv needs to be adjusted.
* @fmt_offset: Value by which wss and sr needs to be adjusted.
+ * @fixed_wss: Hardcoded 'word select size' value needs to be used
+ * @wss_value: Value to be used as WSS if fixed_wss is set
* @field_clkdiv_mclk_en: regmap field to enable mclk output.
* @field_fmt_wss: regmap field to set word select size.
* @field_fmt_sr: regmap field to set sample resolution.
@@ -150,11 +152,13 @@ struct sun4i_i2s_quirks {
bool has_chcfg;
bool has_chsel_tx_chen;
bool has_chsel_offset;
+ bool fixed_wss;
unsigned int reg_offset_txdata; /* TX FIFO */
const struct regmap_config *sun4i_i2s_regmap;
unsigned int mclk_offset;
unsigned int bclk_offset;
unsigned int fmt_offset;
+ unsigned int wss_value;
/* Register fields for i2s */
struct reg_field field_clkdiv_mclk_en;
@@ -345,7 +349,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- int sr, wss, channels;
+ int sr, wss, channels, pwidth;
u32 width;
channels = params_channels(params);
@@ -386,7 +390,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
}
i2s->playback_dma_data.addr_width = width;
- switch (params_width(params)) {
+ pwidth = params_width(params);
+ switch (pwidth) {
case 16:
sr = 0;
wss = 0;
@@ -396,13 +401,30 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ if (i2s->variant->fixed_wss) {
+ wss = i2s->variant->wss_value;
+ switch (wss) {
+ case 0:
+ pwidth = 16;
+ break;
+ case 1:
+ pwidth = 20;
+ break;
+ case 2:
+ pwidth = 24;
+ break;
+ case 3:
+ pwidth = 32;
+ break;
+ }
+ }
+
regmap_field_write(i2s->field_fmt_wss,
wss + i2s->variant->fmt_offset);
regmap_field_write(i2s->field_fmt_sr,
sr + i2s->variant->fmt_offset);
- return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
- params_width(params));
+ return sun4i_i2s_set_clk_rate(i2s, params_rate(params), pwidth);
}
static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
--
2.15.0
^ permalink raw reply related
* [PATCH 0/9] Add audiocodec support for A64 SoC
From: Vasily Khoruzhick @ 2017-12-03 20:41 UTC (permalink / raw)
To: linux-arm-kernel
This series adds A64 audiocodec support into sun4i-i2s, sun8i-codec
and sun8i-codec-analog drivers and enables sound on Pine64 and SoPine
boards.
Marcus Cooper (3):
ASoC: sun4i-i2s: Add compatibility with A64 codec I2S
ASoC: sun8i-codec-analog: Use callbacks to add headphones and lineout
outputs
ASoC: sun8i-codec-analog: Add support for A64 SoC
Vasily Khoruzhick (6):
ASoC: sun4i-i2s: Add quirk to handle fixed WSS
ASoC: sun8i-codec: Add quirk to specify aif1_lrck_div value
ASoC: sun8i-codec: Add support for A64 SoC
ASoC: sun8i-codec-analog: Add component driver field to quirks
structure
arm64: dts: allwinner: a64: Add nodes necessary for analog sound
support
arm64: dts: allwinner: a64: Enable sound on Pine64 and SoPine
.../devicetree/bindings/sound/sun4i-i2s.txt | 2 +
.../bindings/sound/sun8i-codec-analog.txt | 1 +
.../sound/{sun8i-a33-codec.txt => sun8i-codec.txt} | 6 +-
.../arm64/boot/dts/allwinner/sun50i-a64-pine64.dts | 16 ++
.../dts/allwinner/sun50i-a64-sopine-baseboard.dts | 16 ++
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 52 ++++
sound/soc/sunxi/Kconfig | 2 +-
sound/soc/sunxi/sun4i-i2s.c | 53 +++-
sound/soc/sunxi/sun8i-codec-analog.c | 307 ++++++++++++++++++---
sound/soc/sunxi/sun8i-codec.c | 47 +++-
10 files changed, 458 insertions(+), 44 deletions(-)
rename Documentation/devicetree/bindings/sound/{sun8i-a33-codec.txt => sun8i-codec.txt} (91%)
--
2.15.0
^ permalink raw reply
* [PATCH 37/37] KVM: arm/arm64: Avoid VGICv3 save/restore on VHE with no IRQs
From: Christoffer Dall @ 2017-12-03 20:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171130183330.x7jc6m2yffcxcvkz@yury-thinkpad>
Hi Yury,
On Thu, Nov 30, 2017 at 09:33:30PM +0300, Yury Norov wrote:
> On Thu, Oct 12, 2017 at 12:41:41PM +0200, Christoffer Dall wrote:
> > We can finally get completely rid of any calls to the VGICv3
> > save/restore functions when the AP lists are empty on VHE systems. This
> > requires carefully factoring out trap configuration from saving and
> > restoring state, and carefully choosing what to do on the VHE and
> > non-VHE path.
> >
> > One of the challenges is that we cannot save/restore the VMCR lazily
> > because we can only write the VMCR when ICC_SRE_EL1.SRE is cleared when
> > emulating a GICv2-on-GICv3, since otherwise all Group-0 interrupts end
> > up being delivered as FIQ.
> >
> > To solve this problem, and still provide fast performance in the fast
> > path of exiting a VM when no interrupts are pending (which also
> > optimized the latency for actually delivering virtual interrupts coming
> > from physical interrupts), we orchestrate a dance of only doing the
> > activate/deactivate traps in vgic load/put for VHE systems (which can
> > have ICC_SRE_EL1.SRE cleared when running in the host), and doing the
> > configuration on every round-trip on non-VHE systems.
> >
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > arch/arm/include/asm/kvm_hyp.h | 2 +
> > arch/arm/kvm/hyp/switch.c | 8 ++-
> > arch/arm64/include/asm/kvm_hyp.h | 2 +
> > arch/arm64/kvm/hyp/switch.c | 8 ++-
> > virt/kvm/arm/hyp/vgic-v3-sr.c | 116 +++++++++++++++++++++++++--------------
> > virt/kvm/arm/vgic/vgic-v3.c | 6 ++
> > virt/kvm/arm/vgic/vgic.c | 7 +--
> > 7 files changed, 101 insertions(+), 48 deletions(-)
>
> [...]
>
> > diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > index ed5da75..34d71d2 100644
> > --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> > +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > @@ -208,15 +208,15 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
> > {
> > struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> > u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> > - u64 val;
> >
> > /*
> > * Make sure stores to the GIC via the memory mapped interface
> > - * are now visible to the system register interface.
> > + * are now visible to the system register interface when reading the
> > + * LRs, and when reading back the VMCR on non-VHE systems.
> > */
> > - if (!cpu_if->vgic_sre) {
> > - dsb(st);
> > - cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
> > + if (used_lrs || !has_vhe()) {
> > + if (!cpu_if->vgic_sre)
> > + dsb(st);
> > }
>
> Nit:
> if ((used_lrs || !has_vhe()) && !cpu_if->vgic_sre)
> dsb(st);
>
I don't think that's easier to read and I'm not paying for vertical
space, so I'm going to keep it as is.
Thanks,
-Christoffer
^ permalink raw reply
* [PATCH 26/37] KVM: arm64: Prepare to handle traps on deferred AArch32 sysregs
From: Christoffer Dall @ 2017-12-03 20:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171113190701.7vgkady36c6keshh@hawk.localdomain>
On Mon, Nov 13, 2017 at 08:07:01PM +0100, Andrew Jones wrote:
> On Thu, Oct 12, 2017 at 12:41:30PM +0200, Christoffer Dall wrote:
> > Handle accesses to any AArch32 EL1 system registers where we can defer
> > saving and restoring them to vcpu_load and vcpu_put, and which are
> > stored in special EL2 registers only used support 32-bit guests.
> >
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > arch/arm64/kvm/inject_fault.c | 14 +++++++++++++-
> > 1 file changed, 13 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index f4513fc..02990f5 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -59,9 +59,18 @@ static void vcpu_set_elr_el1(struct kvm_vcpu *vcpu, u64 val)
> > /* Set the SPSR for the current mode */
> > static void vcpu_set_spsr(struct kvm_vcpu *vcpu, u64 val)
> > {
> > - if (vcpu_mode_is_32bit(vcpu))
> > + if (vcpu_mode_is_32bit(vcpu)) {
> > + if (vcpu->arch.sysregs_loaded_on_cpu)
> > + __sysreg32_save_state(vcpu);
> > +
> > *vcpu_spsr32(vcpu) = val;
> >
> > + if (vcpu->arch.sysregs_loaded_on_cpu)
> > + __sysreg32_restore_state(vcpu);
> > +
> > + return;
>
> Is this a fix? I don't understand why it's necessary now, but it wasn't
> before.
>
All of these patches are not necessary before "KVM: arm64: Defer
saving/restoring system registers to vcpu load/put on VHE", but I needed
to find a way to split the patches into some smaller pieces, both for
debugging/bisecting and for easing the review.
> > + }
> > +
> > if (vcpu->arch.sysregs_loaded_on_cpu)
> > write_sysreg_el1(val, spsr);
> > else
> > @@ -129,11 +138,13 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
> > * IFAR: mapped to FAR_EL1
> > * DFSR: mapped to ESR_EL1
> > * TTBCR: mapped to TCR_EL1
> > + * IFSR: stored in IFSR32_EL2
> > */
> > if (vcpu->arch.sysregs_loaded_on_cpu) {
> > vcpu->arch.ctxt.sys_regs[FAR_EL1] = read_sysreg_el1(far);
> > vcpu->arch.ctxt.sys_regs[ESR_EL1] = read_sysreg_el1(esr);
> > vcpu->arch.ctxt.sys_regs[TCR_EL1] = read_sysreg_el1(tcr);
> > + vcpu->arch.ctxt.sys_regs[IFSR32_EL2] = read_sysreg(ifsr32_el2);
> > }
> >
> > if (is_pabt) {
> > @@ -161,6 +172,7 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
> > if (vcpu->arch.sysregs_loaded_on_cpu) {
> > write_sysreg_el1(vcpu->arch.ctxt.sys_regs[FAR_EL1], far);
> > write_sysreg_el1(vcpu->arch.ctxt.sys_regs[ESR_EL1], esr);
> > + write_sysreg(vcpu->arch.ctxt.sys_regs[IFSR32_EL2], ifsr32_el2);
>
> This appears to be a fix. Why not squash it into the patch that
> save/restore the other registers?
>
It's just more work we can do before we start being lazy.
I thought it would be easier to review in pieces, and I thought the
sequence of patches begining with "Prepare..." was a commonly used
theme, bt apparently not.
In any cae, this hunk has now gone away due to the shared logic of
32-bit fault injection, so it should be more obvious next time around.
Thanks,
-Christoffer
^ permalink raw reply
* [PATCH 25/37] KVM: arm64: Prepare to handle traps on remaining deferred EL1 sysregs
From: Christoffer Dall @ 2017-12-03 20:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171113185614.6d6xwpyxcnqjfs7w@hawk.localdomain>
On Mon, Nov 13, 2017 at 07:56:14PM +0100, Andrew Jones wrote:
> On Thu, Oct 12, 2017 at 12:41:29PM +0200, Christoffer Dall wrote:
> > Handle accesses during traps to any remaining EL1 registers which can be
> > deferred to vcpu_load and vcpu_put, by either accessing them directly on
> > the physical CPU when the latest version is stored there, or by
> > synchronizing the memory representation with the CPU state.
> >
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > arch/arm64/include/asm/kvm_emulate.h | 14 -------
> > arch/arm64/kvm/inject_fault.c | 79 ++++++++++++++++++++++++++++++++----
> > arch/arm64/kvm/sys_regs.c | 6 ++-
> > 3 files changed, 76 insertions(+), 23 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index 630dd60..69bb40d 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -66,11 +66,6 @@ static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
> > return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
> > }
> >
> > -static inline unsigned long *vcpu_elr_el1(const struct kvm_vcpu *vcpu)
> > -{
> > - return (unsigned long *)&vcpu_gp_regs(vcpu)->elr_el1;
> > -}
> > -
> > static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
> > {
> > return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
> > @@ -120,15 +115,6 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
> > vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
> > }
> >
> > -/* Get vcpu SPSR for current mode */
> > -static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
> > -{
> > - if (vcpu_mode_is_32bit(vcpu))
> > - return vcpu_spsr32(vcpu);
> > -
> > - return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> > -}
> > -
> > static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> > {
> > u32 mode;
> > diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index 45c7026..f4513fc 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -23,6 +23,7 @@
> >
> > #include <linux/kvm_host.h>
> > #include <asm/kvm_emulate.h>
> > +#include <asm/kvm_hyp.h>
> > #include <asm/esr.h>
> >
> > #define PSTATE_FAULT_BITS_64 (PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
> > @@ -33,13 +34,55 @@
> > #define LOWER_EL_AArch64_VECTOR 0x400
> > #define LOWER_EL_AArch32_VECTOR 0x600
> >
> > +static u64 vcpu_get_vbar_el1(struct kvm_vcpu *vcpu)
> > +{
> > + unsigned long vbar;
> > +
> > + if (vcpu->arch.sysregs_loaded_on_cpu)
> > + vbar = read_sysreg_el1(vbar);
> > + else
> > + vbar = vcpu_sys_reg(vcpu, VBAR_EL1);
> > +
> > + if (vcpu_el1_is_32bit(vcpu))
> > + return lower_32_bits(vbar);
> > + return vbar;
> > +}
> > +
> > +static void vcpu_set_elr_el1(struct kvm_vcpu *vcpu, u64 val)
> > +{
> > + if (vcpu->arch.sysregs_loaded_on_cpu)
> > + write_sysreg_el1(val, elr);
> > + else
> > + vcpu_gp_regs(vcpu)->elr_el1 = val;
> > +}
> > +
> > +/* Set the SPSR for the current mode */
> > +static void vcpu_set_spsr(struct kvm_vcpu *vcpu, u64 val)
> > +{
> > + if (vcpu_mode_is_32bit(vcpu))
> > + *vcpu_spsr32(vcpu) = val;
> > +
> > + if (vcpu->arch.sysregs_loaded_on_cpu)
> > + write_sysreg_el1(val, spsr);
> > + else
> > + vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = val;
> > +}
> > +
> > +static u32 vcpu_get_c1_sctlr(struct kvm_vcpu *vcpu)
> > +{
> > + if (vcpu->arch.sysregs_loaded_on_cpu)
> > + return lower_32_bits(read_sysreg_el1(sctlr));
> > + else
> > + return vcpu_cp15(vcpu, c1_SCTLR);
> > +}
> > +
> > static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
> > {
> > unsigned long cpsr;
> > unsigned long new_spsr_value = *vcpu_cpsr(vcpu);
> > bool is_thumb = (new_spsr_value & COMPAT_PSR_T_BIT);
> > u32 return_offset = (is_thumb) ? 4 : 0;
> > - u32 sctlr = vcpu_cp15(vcpu, c1_SCTLR);
> > + u32 sctlr = vcpu_get_c1_sctlr(vcpu);
> >
> > cpsr = mode | COMPAT_PSR_I_BIT;
> >
> > @@ -51,14 +94,14 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
> > *vcpu_cpsr(vcpu) = cpsr;
> >
> > /* Note: These now point to the banked copies */
> > - *vcpu_spsr(vcpu) = new_spsr_value;
> > + vcpu_set_spsr(vcpu, new_spsr_value);
> > *vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
> >
> > /* Branch to exception vector */
> > if (sctlr & (1 << 13))
> > vect_offset += 0xffff0000;
> > else /* always have security exceptions */
> > - vect_offset += vcpu_cp15(vcpu, c12_VBAR);
> > + vect_offset += vcpu_get_vbar_el1(vcpu);
> >
> > *vcpu_pc(vcpu) = vect_offset;
> > }
> > @@ -79,6 +122,20 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
> > u32 *far, *fsr;
> > bool is_lpae;
> >
> > + /*
> > + * We are going to need the latest values of the following system
> > + * regiters:
>
> registers
>
> > + * DFAR: mapped to FAR_EL1
>
> FAR_EL1[31:0]
>
> > + * IFAR: mapped to FAR_EL1
>
> FAR_EL1[63:32]
>
I had to rework this after the 32-bit fault injection code has been
reworked, so I got rid of this comment (as it's now being shared with
the 32-bit side, and I use a bigger hammer to solve the problem).
> > + * DFSR: mapped to ESR_EL1
> > + * TTBCR: mapped to TCR_EL1
> > + */
> > + if (vcpu->arch.sysregs_loaded_on_cpu) {
> > + vcpu->arch.ctxt.sys_regs[FAR_EL1] = read_sysreg_el1(far);
> > + vcpu->arch.ctxt.sys_regs[ESR_EL1] = read_sysreg_el1(esr);
> > + vcpu->arch.ctxt.sys_regs[TCR_EL1] = read_sysreg_el1(tcr);
> > + }
> > +
> > if (is_pabt) {
> > vect_offset = 12;
> > far = &vcpu_cp15(vcpu, c6_IFAR);
> > @@ -99,6 +156,12 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
> > *fsr = 1 << 9 | 0x34;
> > else
> > *fsr = 0x14;
> > +
> > + /* Sync back any registers we may have changed */
> > + if (vcpu->arch.sysregs_loaded_on_cpu) {
> > + write_sysreg_el1(vcpu->arch.ctxt.sys_regs[FAR_EL1], far);
> > + write_sysreg_el1(vcpu->arch.ctxt.sys_regs[ESR_EL1], esr);
> > + }
> > }
> >
> > enum exception_type {
> > @@ -126,7 +189,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
> > exc_offset = LOWER_EL_AArch32_VECTOR;
> > }
> >
> > - return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> > + return vcpu_get_vbar_el1(vcpu) + exc_offset + type;
> > }
> >
> > static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
> > @@ -135,11 +198,11 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
> > bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
> > u32 esr = 0;
> >
> > - *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
> > + vcpu_set_elr_el1(vcpu, *vcpu_pc(vcpu));
> > *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
> >
> > *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> > - *vcpu_spsr(vcpu) = cpsr;
> > + vcpu_set_spsr(vcpu, cpsr);
> >
> > vcpu_sys_reg(vcpu, FAR_EL1) = addr;
> >
> > @@ -170,11 +233,11 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
> > unsigned long cpsr = *vcpu_cpsr(vcpu);
> > u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
> >
> > - *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
> > + vcpu_set_elr_el1(vcpu, *vcpu_pc(vcpu));
> > *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
> >
> > *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> > - *vcpu_spsr(vcpu) = cpsr;
> > + vcpu_set_spsr(vcpu, cpsr);
> >
>
> I'm concerned the maintenance of emulation code will become more
> difficult now that some registers have special accessors, while
> others don't, and some functions have save/restore lists, that
> will need to stay maintained with the emulation. The only alternative
> that pops to mind, though, is adding get/set members to the register
> descriptors and encapsulating the decision in them, but that might be
> overkill.
>
I was concerned initially as well, and had rewritten the entire code to
use get/set accessors everywhere, and that was not a pretty set of
patches to review, and in fact seemed less intuitive and easy to
maintain.
This is an interesting discussion; my original standpoint was very
similar to yours and I had similar concernes, but this rework has left
me feeling that maintaining this code base requires an intimate
understanding of the flow and state the CPU/VM can be in at any one
point, and it's therefore actually easier to maintain something that
does the required things in the right places, as opposed to creating
larger abstractions, at least to some degree.
I'm curious what Marc thinks here, and I'm willing to produce an
alternative patch with everything abstracted as get/set functions, with
giant switch statements to access hardware registers (which will only
actually hit in a few of the cases), but I think I know what the final
answer will be already.
> > /*
> > * Build an unknown exception, depending on the instruction
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index f7887dd..60d1660 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -86,12 +86,16 @@ static u32 cache_levels;
> > static u32 get_ccsidr(u32 csselr)
> > {
> > u32 ccsidr;
> > + u32 csselr_preserve;
> >
> > - /* Make sure noone else changes CSSELR during this! */
> > + /* Make sure noone else changes CSSELR during this and preserve any
> > + * existing value in the CSSELR! */
> > local_irq_disable();
> > + csselr_preserve = read_sysreg(csselr_el1);
> > write_sysreg(csselr, csselr_el1);
> > isb();
> > ccsidr = read_sysreg(ccsidr_el1);
> > + write_sysreg(csselr_preserve, csselr_el1);
> > local_irq_enable();
> >
> > return ccsidr;
>
> This looks like an unrelated fix.
>
Not really. The point is that the host kernel doesn't make any
assumptions about the csselr and will set it to select the value it
wants to read when using this feature.
Until we start deferring el1 registers for the guest, we can therefore
do the same, as the guest will always get its values restore.
However, when we introduce lazy save/restore of guest state, we cannot
just step on the guest state, but we have to preserve the guest state.
We could make it conditional on the sysregs loaded flag, but that
doesn't get us much, and we might as well do this.
Thanks,
-Christoffer
^ permalink raw reply
* [PATCH 1/2] arm64: dts: orange-pi-zero-plus2: fix sdcard detect
From: Sergey Matyukevich @ 2017-12-03 20:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMty3ZDQqaiZ0RxtngWdX9PCW2+tzXLVB64heHLjRBeVF2-FCQ@mail.gmail.com>
Hello Maxime,
> >> > Do you plan to accept this patch as well ? Or you would prefer to wait
> >> > for the confirmation from Jagan as well ?
> >>
> >> I'm happy with the patch, but I was under the impression that the
> >> discussion had not settled yet. If it did, then yeah I'll merge it :)
> >
> > Both schematics and my tests on v1.0 board confirm that this fix is ok.
> > However we haven't yet got the ACK from Jagan, the original submitter
> > of this dts file. FWIW discussion was mostly about the problems with
> > his setup and not about the fix itself.
> >
> > Jagan,
> > did you have a chance to resolve the issues with your setup and verify
> > that boot from sd-card is fixed by this patch ?
>
> Acked-by: Jagan Teki <jagan@openedev.com>
It looks like discussion has finally settled: here is ACK from Jagan.
Could you please take this patch.
Regards,
Sergey
^ permalink raw reply
* [PATCH] ARM: da850: Fix LEGO EV3 battery voltage gpio
From: David Lechner @ 2017-12-03 19:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1512329373-17321-1-git-send-email-david@lechnology.com>
On 12/03/2017 01:29 PM, David Lechner wrote:
> This fixes the battery voltage monitoring gpio-hog settings.
>
> When the gpio is low, it turns off the battery voltage to the ADC chip.
> However, this needs to be on all of the time so that we can monitor
> battery voltage.
>
> Signed-off-by: David Lechner <david@lechnology.com>
> ---
Please disregard this patch. Apparently, pinmuxing on platform devices
is broken in the linux-davinci master branch, which led me astray.
^ permalink raw reply
* [PATCH 24/37] KVM: arm64: Prepare to handle traps on deferred EL0 sysregs
From: Christoffer Dall @ 2017-12-03 19:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <ff71a471-4a16-806c-c355-15bf778c7d98@arm.com>
On Wed, Nov 15, 2017 at 09:25:08AM +0000, Julien Thierry wrote:
>
>
> On 12/10/17 11:41, Christoffer Dall wrote:
> >We can trap access to ACTLR_EL1 which we can later defer to only
> >save/restore during vcpu_load and vcpu_put, so let's read the value
> >directly from the CPU when necessary.
> >
> >Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >---
> > arch/arm64/kvm/sys_regs_generic_v8.c | 5 ++++-
> > 1 file changed, 4 insertions(+), 1 deletion(-)
> >
> >diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
> >index 969ade1..348f227 100644
> >--- a/arch/arm64/kvm/sys_regs_generic_v8.c
> >+++ b/arch/arm64/kvm/sys_regs_generic_v8.c
> >@@ -38,7 +38,10 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
> > if (p->is_write)
> > return ignore_write(vcpu, p);
> >- p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
> >+ if (vcpu->arch.sysregs_loaded_on_cpu)
> >+ read_sysreg(actlr_el1);
>
> Did you mean "p->regval = read_sysreg(actlr_el1);" ?
>
> >+ else
> >+ p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
> > return true;
> > }
> >
>
Yes, most certainly. Nice catch.
Thanks,
-Christoffer
^ permalink raw reply
* [PATCH 23/37] KVM: arm64: Prepare to handle traps on deferred VM sysregs
From: Christoffer Dall @ 2017-12-03 19:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171113175402.rw3on4vps2o24q4d@hawk.localdomain>
On Mon, Nov 13, 2017 at 06:54:02PM +0100, Andrew Jones wrote:
> On Thu, Oct 12, 2017 at 12:41:27PM +0200, Christoffer Dall wrote:
> > When we defer the save/restore of system registers to vcpu_load and
> > vcpu_put, we need to take care of the emulation code that handles traps
> > to these registers, since simply reading the memory array will return
> > stale data.
> >
> > Therefore, introduce two functions to directly read/write the registers
> > from the physical CPU when we're on a VHE system that has loaded the
> > system registers onto the physical CPU.
> >
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > arch/arm64/include/asm/kvm_host.h | 4 +++
> > arch/arm64/kvm/sys_regs.c | 54 +++++++++++++++++++++++++++++++++++++--
> > 2 files changed, 56 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 9f5761f..dcded44 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -278,6 +278,10 @@ struct kvm_vcpu_arch {
> >
> > /* Detect first run of a vcpu */
> > bool has_run_once;
> > +
> > + /* True when deferrable sysregs are loaded on the physical CPU,
> > + * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
> > + bool sysregs_loaded_on_cpu;
>
> To be sure I understand correctly, this should only be false when we're
> servicing ioctls that don't do a full vcpu_load first (non-KVM_RUN) or
> when we're not running on a CPU with VHE. If we didn't need to worry
> about non-KVM_RUN ioctls, then we could use the static key has_vhe(),
> right?
>
That is correct, if we also liked the idea of replacing the entire CPU
state every time we read/write a single register from user space.
However, as this isn't performance critical, I'd much rather have a flag
that tells me where to go look for the latest value of a system
register.
> > };
> >
> > #define vcpu_gp_regs(v) (&(v)->arch.ctxt.gp_regs)
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index dbe35fd..f7887dd 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -34,6 +34,7 @@
> > #include <asm/kvm_coproc.h>
> > #include <asm/kvm_emulate.h>
> > #include <asm/kvm_host.h>
> > +#include <asm/kvm_hyp.h>
> > #include <asm/kvm_mmu.h>
> > #include <asm/perf_event.h>
> > #include <asm/sysreg.h>
> > @@ -110,8 +111,57 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
> > return true;
> > }
> >
> > +static u64 read_deferrable_vm_reg(struct kvm_vcpu *vcpu, int reg)
> > +{
> > + if (vcpu->arch.sysregs_loaded_on_cpu) {
> > + switch (reg) {
> > + case SCTLR_EL1: return read_sysreg_el1(sctlr);
> > + case TTBR0_EL1: return read_sysreg_el1(ttbr0);
> > + case TTBR1_EL1: return read_sysreg_el1(ttbr1);
> > + case TCR_EL1: return read_sysreg_el1(tcr);
> > + case ESR_EL1: return read_sysreg_el1(esr);
> > + case FAR_EL1: return read_sysreg_el1(far);
> > + case AFSR0_EL1: return read_sysreg_el1(afsr0);
> > + case AFSR1_EL1: return read_sysreg_el1(afsr1);
> > + case MAIR_EL1: return read_sysreg_el1(mair);
> > + case AMAIR_EL1: return read_sysreg_el1(amair);
> > + case CONTEXTIDR_EL1: return read_sysreg_el1(contextidr);
> > + case DACR32_EL2: return read_sysreg(dacr32_el2);
> > + case IFSR32_EL2: return read_sysreg(ifsr32_el2);
> > + default: BUG();
> > + }
> > + }
> > +
> > + return vcpu_sys_reg(vcpu, reg);
> > +}
> > +
> > +static void write_deferrable_vm_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> > +{
> > + if (vcpu->arch.sysregs_loaded_on_cpu) {
> > + switch (reg) {
> > + case SCTLR_EL1: write_sysreg_el1(val, sctlr); return;
> > + case TTBR0_EL1: write_sysreg_el1(val, ttbr0); return;
> > + case TTBR1_EL1: write_sysreg_el1(val, ttbr1); return;
> > + case TCR_EL1: write_sysreg_el1(val, tcr); return;
> > + case ESR_EL1: write_sysreg_el1(val, esr); return;
> > + case FAR_EL1: write_sysreg_el1(val, far); return;
> > + case AFSR0_EL1: write_sysreg_el1(val, afsr0); return;
> > + case AFSR1_EL1: write_sysreg_el1(val, afsr1); return;
> > + case MAIR_EL1: write_sysreg_el1(val, mair); return;
> > + case AMAIR_EL1: write_sysreg_el1(val, amair); return;
> > + case CONTEXTIDR_EL1: write_sysreg_el1(val, contextidr); return;
> > + case DACR32_EL2: write_sysreg(val, dacr32_el2); return;
> > + case IFSR32_EL2: write_sysreg(val, ifsr32_el2); return;
> > + default: BUG();
> > + }
> > + }
> > +
> > + vcpu_sys_reg(vcpu, reg) = val;
> > +}
> > +
> > /*
> > * Generic accessor for VM registers. Only called as long as HCR_TVM
> > + *
> > * is set. If the guest enables the MMU, we stop trapping the VM
> > * sys_regs and leave it in complete control of the caches.
> > */
> > @@ -132,14 +182,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
> > if (!p->is_aarch32 || !p->is_32bit) {
> > val = p->regval;
> > } else {
> > - val = vcpu_sys_reg(vcpu, reg);
> > + val = read_deferrable_vm_reg(vcpu, reg);
> > if (r->reg % 2)
> > val = (p->regval << 32) | (u64)lower_32_bits(val);
> > else
> > val = ((u64)upper_32_bits(val) << 32) |
> > (u64)lower_32_bits(p->regval);
> > }
> > - vcpu_sys_reg(vcpu, reg) = val;
> > + write_deferrable_vm_reg(vcpu, reg, val);
> >
> > kvm_toggle_cache(vcpu, was_enabled);
> > return true;
> > --
> > 2.9.0
> >
>
> I read ahead and see other wrappers that check sysregs_loaded_on_cpu are
> added, but only write_deferrable_vm_reg() has 'deferrable' in its name.
> Should it just be named read/write_vm_reg?
>
I chose this name to avoid implying that this function was universally
supported for all (current and future) VM registers.
Thanks,
-Christoffer
^ permalink raw reply
* [PATCH 21/37] KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems
From: Christoffer Dall @ 2017-12-03 19:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171108170323.q5ikpwgruos3giay@kamzik.brq.redhat.com>
On Wed, Nov 08, 2017 at 06:03:23PM +0100, Andrew Jones wrote:
> On Thu, Oct 12, 2017 at 12:41:25PM +0200, Christoffer Dall wrote:
> > On non-VHE systems we need to save the ELR_EL2 and SPSR_EL2 so that we
> > can return to the host in EL1 in the same state and location where we
> > issued a hypercall to EL2, but these registers don't contain anything
> > important on VHE, because all of the host runs in EL2. Therefore,
> > exclude them when saving/restoring the host state.
>
> This commit message implies we start excluding now, but this patch
> actually has no functional change. It just prepares things for
> patch 27/37 "KVM: arm64: Defer saving/restoring system registers to
> vcpu load/put on VHE". Can you please clarify it?
>
Sure:
On non-VHE systems we need to save the ELR_EL2 and SPSR_EL2 so that we
can return to the host in EL1 in the same state and location where we
issued a hypercall to EL2, but these registers don't contain anything
important on VHE, because all of the host runs in EL2. Therefore,
factor out these registers into separate save/restore functions, making
it easy to exclude them from the VHE world-switch path later on.
Thanks,
-Christoffer
>
> >
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > arch/arm64/kvm/hyp/sysreg-sr.c | 13 +++++++++++++
> > 1 file changed, 13 insertions(+)
> >
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index f5c1b44..354ca02 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -66,6 +66,10 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
> > ctxt->gp_regs.sp_el1 = read_sysreg(sp_el1);
> > ctxt->gp_regs.elr_el1 = read_sysreg_el1(elr);
> > ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg_el1(spsr);
> > +}
> > +
> > +static void __hyp_text __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt)
> > +{
> > ctxt->gp_regs.regs.pc = read_sysreg_el2(elr);
> > ctxt->gp_regs.regs.pstate = read_sysreg_el2(spsr);
> > }
> > @@ -75,6 +79,7 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
> > __sysreg_save_el1_state(ctxt);
> > __sysreg_save_common_state(ctxt);
> > __sysreg_save_user_state(ctxt);
> > + __sysreg_save_el2_return_state(ctxt);
> > }
> >
> > void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
> > @@ -88,6 +93,7 @@ void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
> > __sysreg_save_el1_state(ctxt);
> > __sysreg_save_common_state(ctxt);
> > __sysreg_save_user_state(ctxt);
> > + __sysreg_save_el2_return_state(ctxt);
> > }
> >
> > static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
> > @@ -127,6 +133,11 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
> > write_sysreg(ctxt->gp_regs.sp_el1, sp_el1);
> > write_sysreg_el1(ctxt->gp_regs.elr_el1, elr);
> > write_sysreg_el1(ctxt->gp_regs.spsr[KVM_SPSR_EL1],spsr);
> > +}
> > +
> > +static void __hyp_text
> > +__sysreg_restore_el2_return_state(struct kvm_cpu_context *ctxt)
> > +{
> > write_sysreg_el2(ctxt->gp_regs.regs.pc, elr);
> > write_sysreg_el2(ctxt->gp_regs.regs.pstate, spsr);
> > }
> > @@ -136,6 +147,7 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
> > __sysreg_restore_el1_state(ctxt);
> > __sysreg_restore_common_state(ctxt);
> > __sysreg_restore_user_state(ctxt);
> > + __sysreg_restore_el2_return_state(ctxt);
> > }
> >
> > void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
> > @@ -149,6 +161,7 @@ void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
> > __sysreg_restore_el1_state(ctxt);
> > __sysreg_restore_common_state(ctxt);
> > __sysreg_restore_user_state(ctxt);
> > + __sysreg_restore_el2_return_state(ctxt);
> > }
> >
> > static void __hyp_text __fpsimd32_save_state(struct kvm_cpu_context *ctxt)
> > --
> > 2.9.0
> >
^ permalink raw reply
* [PATCH 20/37] KVM: arm64: Unify non-VHE host/guest sysreg save and restore functions
From: Christoffer Dall @ 2017-12-03 19:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171108103906.d7jgzzlt4dxpae6k@kamzik.brq.redhat.com>
On Wed, Nov 08, 2017 at 11:39:06AM +0100, Andrew Jones wrote:
> On Thu, Oct 12, 2017 at 12:41:24PM +0200, Christoffer Dall wrote:
> > There is no need to have multiple identical functions with different
> > names for saving host and guest state. When saving and restoring state
> > for the host and guest, the state is the same for both contexts, and
> > that's why we have the kvm_cpu_context structure. Delete one
> > version and rename the other into simply save/restore.
> >
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > arch/arm64/include/asm/kvm_hyp.h | 6 ++----
> > arch/arm64/kvm/hyp/switch.c | 10 +++++-----
> > arch/arm64/kvm/hyp/sysreg-sr.c | 18 ++----------------
> > 3 files changed, 9 insertions(+), 25 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> > index 998152d..3f54c55 100644
> > --- a/arch/arm64/include/asm/kvm_hyp.h
> > +++ b/arch/arm64/include/asm/kvm_hyp.h
> > @@ -132,10 +132,8 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
> > void __timer_enable_traps(struct kvm_vcpu *vcpu);
> > void __timer_disable_traps(struct kvm_vcpu *vcpu);
> >
> > -void __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt);
> > -void __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt);
> > -void __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt);
> > -void __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt);
> > +void __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt);
> > +void __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt);
> > void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt);
> > void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt);
> > void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt);
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 7c4d430..6356bec 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -383,7 +383,7 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
> > host_ctxt->__hyp_running_vcpu = vcpu;
> > guest_ctxt = &vcpu->arch.ctxt;
> >
> > - __sysreg_save_host_state_nvhe(host_ctxt);
> > + __sysreg_save_state_nvhe(host_ctxt);
> >
> > __activate_traps(vcpu);
> > __activate_vm(vcpu);
> > @@ -396,7 +396,7 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
> > * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> > */
> > __sysreg32_restore_state(vcpu);
> > - __sysreg_restore_guest_state_nvhe(guest_ctxt);
> > + __sysreg_restore_state_nvhe(guest_ctxt);
> > __debug_switch_to_guest(vcpu);
> >
> > /* Jump in the fire! */
> > @@ -407,7 +407,7 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
> > if (fixup_guest_exit(vcpu, &exit_code))
> > goto again;
> >
> > - __sysreg_save_guest_state_nvhe(guest_ctxt);
> > + __sysreg_save_state_nvhe(guest_ctxt);
> > __sysreg32_save_state(vcpu);
> > __timer_disable_traps(vcpu);
> > __vgic_save_state(vcpu);
> > @@ -415,7 +415,7 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
> > __deactivate_traps(vcpu);
> > __deactivate_vm(vcpu);
> >
> > - __sysreg_restore_host_state_nvhe(host_ctxt);
> > + __sysreg_restore_state_nvhe(host_ctxt);
> >
> > /*
> > * This must come after restoring the host sysregs, since a non-VHE
> > @@ -440,7 +440,7 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
> > __timer_disable_traps(vcpu);
> > __deactivate_traps(vcpu);
> > __deactivate_vm(vcpu);
> > - __sysreg_restore_host_state_nvhe(__host_ctxt);
> > + __sysreg_restore_state_nvhe(__host_ctxt);
> > }
> >
> > /*
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index d8c42de..f5c1b44 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -70,14 +70,7 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
> > ctxt->gp_regs.regs.pstate = read_sysreg_el2(spsr);
> > }
> >
> > -void __hyp_text __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt)
> > -{
> > - __sysreg_save_el1_state(ctxt);
> > - __sysreg_save_common_state(ctxt);
> > - __sysreg_save_user_state(ctxt);
> > -}
> > -
> > -void __hyp_text __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt)
> > +void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
> > {
> > __sysreg_save_el1_state(ctxt);
> > __sysreg_save_common_state(ctxt);
> > @@ -138,14 +131,7 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
> > write_sysreg_el2(ctxt->gp_regs.regs.pstate, spsr);
> > }
> >
> > -void __hyp_text __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt)
> > -{
> > - __sysreg_restore_el1_state(ctxt);
> > - __sysreg_restore_common_state(ctxt);
> > - __sysreg_restore_user_state(ctxt);
> > -}
> > -
> > -void __hyp_text __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt)
> > +void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
> > {
> > __sysreg_restore_el1_state(ctxt);
> > __sysreg_restore_common_state(ctxt);
> > --
> > 2.9.0
> >
>
> I think this patch could be squashed into the last one without
> complicating the review. Anyway
This series was hard to debug, so I made changes as small as possible to
maintain my sanity when bisecting.
>
> Reviewed-by: Andrew Jones <drjones@redhat.com>
Thanks,
-Christoffer
^ permalink raw reply
* [PATCH 17/37] KVM: arm64: Move userspace system registers into separate function
From: Christoffer Dall @ 2017-12-03 19:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171108093230.kusus6zsrf5jbkr6@kamzik.brq.redhat.com>
On Wed, Nov 08, 2017 at 10:32:30AM +0100, Andrew Jones wrote:
> On Thu, Oct 12, 2017 at 12:41:21PM +0200, Christoffer Dall wrote:
> > There's a semantic difference between the EL1 registers that control
> > operation of a kernel running in EL1 and EL1 registers that only control
> > userspace execution in EL0. Since we can defer saving/restoring the
> > latter, move them into their own function.
> >
> > We also take this chance to rename the function saving/restoring the
> > remaining system register to make it clear this function deals with
> > the EL1 system registers.
> >
> > No functional change.
> >
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > arch/arm64/kvm/hyp/sysreg-sr.c | 34 +++++++++++++++++++++++-----------
> > 1 file changed, 23 insertions(+), 11 deletions(-)
> >
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index c4a3714..193c2b0 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -34,14 +34,18 @@ static void __hyp_text __sysreg_do_nothing(struct kvm_cpu_context *ctxt) { }
> >
> > static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
> > {
> > + ctxt->sys_regs[MDSCR_EL1] = read_sysreg(mdscr_el1);
> > + ctxt->gp_regs.regs.sp = read_sysreg(sp_el0);
>
> Maybe a comment stating that sp_el0 is here, instead of down in user
> state, because arm64 Linux chooses to use it for the 'current' pointer.
> At least that's why I think it's been promoted to common state, but maybe
> there was a different reason I missed.
>
That is the reason. I can add a comment.
> > +}
> > +
> > +static void __hyp_text __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
> > +{
> > ctxt->sys_regs[ACTLR_EL1] = read_sysreg(actlr_el1);
> > ctxt->sys_regs[TPIDR_EL0] = read_sysreg(tpidr_el0);
> > ctxt->sys_regs[TPIDRRO_EL0] = read_sysreg(tpidrro_el0);
> > - ctxt->sys_regs[MDSCR_EL1] = read_sysreg(mdscr_el1);
> > - ctxt->gp_regs.regs.sp = read_sysreg(sp_el0);
> > }
> >
> > -static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
> > +static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
> > {
> > ctxt->sys_regs[MPIDR_EL1] = read_sysreg(vmpidr_el2);
> > ctxt->sys_regs[CSSELR_EL1] = read_sysreg(csselr_el1);
> > @@ -70,31 +74,37 @@ static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
> > }
> >
> > static hyp_alternate_select(__sysreg_call_save_host_state,
> > - __sysreg_save_state, __sysreg_do_nothing,
> > + __sysreg_save_el1_state, __sysreg_do_nothing,
> > ARM64_HAS_VIRT_HOST_EXTN);
> >
> > void __hyp_text __sysreg_save_host_state(struct kvm_cpu_context *ctxt)
> > {
> > __sysreg_call_save_host_state()(ctxt);
> > __sysreg_save_common_state(ctxt);
> > + __sysreg_save_user_state(ctxt);
> > }
> >
> > void __hyp_text __sysreg_save_guest_state(struct kvm_cpu_context *ctxt)
> > {
> > - __sysreg_save_state(ctxt);
> > + __sysreg_save_el1_state(ctxt);
> > __sysreg_save_common_state(ctxt);
> > + __sysreg_save_user_state(ctxt);
> > }
> >
> > static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
> > {
> > - write_sysreg(ctxt->sys_regs[ACTLR_EL1], actlr_el1);
> > - write_sysreg(ctxt->sys_regs[TPIDR_EL0], tpidr_el0);
> > - write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0);
> > write_sysreg(ctxt->sys_regs[MDSCR_EL1], mdscr_el1);
> > write_sysreg(ctxt->gp_regs.regs.sp, sp_el0);
> > }
> >
> > -static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
> > +static void __hyp_text __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
> > +{
> > + write_sysreg(ctxt->sys_regs[ACTLR_EL1], actlr_el1);
> > + write_sysreg(ctxt->sys_regs[TPIDR_EL0], tpidr_el0);
> > + write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0);
> > +}
> > +
> > +static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
> > {
> > write_sysreg(ctxt->sys_regs[MPIDR_EL1], vmpidr_el2);
> > write_sysreg(ctxt->sys_regs[CSSELR_EL1], csselr_el1);
> > @@ -123,19 +133,21 @@ static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
> > }
> >
> > static hyp_alternate_select(__sysreg_call_restore_host_state,
> > - __sysreg_restore_state, __sysreg_do_nothing,
> > + __sysreg_restore_el1_state, __sysreg_do_nothing,
> > ARM64_HAS_VIRT_HOST_EXTN);
> >
> > void __hyp_text __sysreg_restore_host_state(struct kvm_cpu_context *ctxt)
> > {
> > __sysreg_call_restore_host_state()(ctxt);
> > __sysreg_restore_common_state(ctxt);
> > + __sysreg_restore_user_state(ctxt);
> > }
> >
> > void __hyp_text __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt)
> > {
> > - __sysreg_restore_state(ctxt);
> > + __sysreg_restore_el1_state(ctxt);
> > __sysreg_restore_common_state(ctxt);
> > + __sysreg_restore_user_state(ctxt);
> > }
> >
> > static void __hyp_text __fpsimd32_save_state(struct kvm_cpu_context *ctxt)
> > --
> > 2.9.0
> >
>
> Otherwise
>
> Reviewed-by: Andrew Jones <drjones@redhat.com>
Thanks,
-Christoffer
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox