* [PATCH v4 3/9] dt-bindings: input: touchscreen: add pressure threshold touchscreen property
From: Dmitry Torokhov @ 2018-05-07 22:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525084335-11276-4-git-send-email-eugen.hristev@microchip.com>
On Mon, Apr 30, 2018 at 01:32:09PM +0300, Eugen Hristev wrote:
> Add a common touchscreen optional property that will specify
> the minimum pressure applied to the screen that is needed
> such that the driver will report the touch event.
>
> Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
> index 537643e..c84047a 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
> +++ b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
> @@ -7,6 +7,9 @@ Optional properties for Touchscreens:
> (in pixels)
> - touchscreen-max-pressure : maximum reported pressure (arbitrary range
> dependent on the controller)
> + - touchscreen-threshold-pressure: minimum pressure on the touchscreen to be
> + achieved in order for the touchscreen
> + driver to report a touch event.
Why do we move from the pattern and call it trheshold and not
touchscreen-min-pressure?
> - touchscreen-fuzz-x : horizontal noise value of the absolute input
> device (in pixels)
> - touchscreen-fuzz-y : vertical noise value of the absolute input
> --
> 2.7.4
>
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH v2 24/27] coresight: tmc-etr: Relax collection of trace from sysfs mode
From: Mathieu Poirier @ 2018-05-07 22:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525165857-11096-25-git-send-email-suzuki.poulose@arm.com>
On Tue, May 01, 2018 at 10:10:54AM +0100, Suzuki K Poulose wrote:
> Since the ETR now uses mode specific buffers, we can reliably
> provide the trace data captured in sysfs mode, even when the ETR
> is operating in PERF mode.
>
> Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-tmc-etr.c | 14 ++++++--------
> 1 file changed, 6 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index a35a12f..7551272 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -1439,19 +1439,17 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
> goto out;
> }
>
> - /* Don't interfere if operated from Perf */
> - if (drvdata->mode == CS_MODE_PERF) {
> - ret = -EINVAL;
> - goto out;
> - }
> -
> - /* If sysfs_buf is NULL the trace data has been read already */
> + /*
> + * We can safely allow reads even if the ETR is operating in PERF mode,
> + * since the sysfs session is captured in mode specific data.
> + * If drvdata::sysfs_data is NULL the trace data has been read already.
> + */
> if (!drvdata->sysfs_buf) {
> ret = -EINVAL;
> goto out;
> }
>
> - /* Disable the TMC if we are trying to read from a running session */
> + /* Disable the TMC if we are trying to read from a running session. */
Move that to the previous patch.
> if (drvdata->mode == CS_MODE_SYSFS)
> tmc_etr_disable_hw(drvdata);
>
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH v2 1/2] arm64: dts: Add msm8998 SoC and MTP board support
From: Stephen Boyd @ 2018-05-07 22:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180428054248.22387-1-bjorn.andersson@linaro.org>
Quoting Bjorn Andersson (2018-04-27 22:42:47)
> diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> new file mode 100644
> index 000000000000..d6665e4f801f
> --- /dev/null
> +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> @@ -0,0 +1,340 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. */
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/clock/qcom,gcc-msm8998.h>
> +
> +/ {
> + model = "Qualcomm Technologies, Inc. MSM 8998";
> +
> + interrupt-parent = <&intc>;
> +
> + qcom,msm-id = <292 0x0>;
No update to dtbtool?
> +
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + chosen { };
> +
> + memory {
> + device_type = "memory";
> + /* We expect the bootloader to fill in the reg */
> + reg = <0 0 0 0>;
> + };
> +
> + cpus {
> + #address-cells = <2>;
> + #size-cells = <0>;
> +
> + CPU0: cpu at 0 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x0>;
> + enable-method = "psci";
> + efficiency = <1024>;
> + next-level-cache = <&L2_0>;
> + L2_0: l2-cache {
> + compatible = "arm,arch-cache";
> + cache-level = <2>;
> + };
> + L1_I_0: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_0: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU1: cpu at 1 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x1>;
> + enable-method = "psci";
> + efficiency = <1024>;
> + next-level-cache = <&L2_0>;
> + L1_I_1: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_1: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU2: cpu at 2 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x2>;
> + enable-method = "psci";
> + efficiency = <1024>;
> + next-level-cache = <&L2_0>;
> + L1_I_2: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_2: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU3: cpu at 3 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x3>;
> + enable-method = "psci";
> + efficiency = <1024>;
> + next-level-cache = <&L2_0>;
> + L1_I_3: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_3: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU4: cpu at 100 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x100>;
> + enable-method = "psci";
> + efficiency = <1536>;
> + next-level-cache = <&L2_1>;
> + L2_1: l2-cache {
> + compatible = "arm,arch-cache";
> + cache-level = <2>;
> + };
> + L1_I_100: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_100: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU5: cpu at 101 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x101>;
> + enable-method = "psci";
> + efficiency = <1536>;
> + next-level-cache = <&L2_1>;
> + L1_I_101: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_101: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU6: cpu at 102 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x102>;
> + enable-method = "psci";
> + efficiency = <1536>;
> + next-level-cache = <&L2_1>;
> + L1_I_102: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_102: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + CPU7: cpu at 103 {
> + device_type = "cpu";
> + compatible = "arm,armv8";
> + reg = <0x0 0x103>;
> + enable-method = "psci";
> + efficiency = <1536>;
> + next-level-cache = <&L2_1>;
> + L1_I_103: l1-icache {
> + compatible = "arm,arch-cache";
> + };
> + L1_D_103: l1-dcache {
> + compatible = "arm,arch-cache";
> + };
> + };
> +
> + cpu-map {
> + cluster0 {
> + core0 {
> + cpu = <&CPU0>;
> + };
> +
> + core1 {
> + cpu = <&CPU1>;
> + };
> +
> + core2 {
> + cpu = <&CPU2>;
> + };
> +
> + core3 {
> + cpu = <&CPU3>;
> + };
> + };
> +
> + cluster1 {
> + core0 {
> + cpu = <&CPU4>;
> + };
> +
> + core1 {
> + cpu = <&CPU5>;
> + };
> +
> + core2 {
> + cpu = <&CPU6>;
> + };
> +
> + core3 {
> + cpu = <&CPU7>;
> + };
> + };
> + };
I still wonder if this is accurate, but OK.
> + };
> +
> + timer {
> + compatible = "arm,armv8-timer";
> + interrupts = <GIC_PPI 1 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_PPI 2 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_PPI 3 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_PPI 0 IRQ_TYPE_LEVEL_LOW>;
> + };
> +
> + clocks {
> + xo_board {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <19200000>;
> + };
> +
> + sleep_clk {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <32764>;
> + };
> + };
> +
> + psci {
> + compatible = "arm,psci-1.0";
> + method = "smc";
> + };
> +
> + soc: soc {};
> +};
> +
> +&soc {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0 0 0 0xffffffff>;
> + compatible = "simple-bus";
> +
> + intc: interrupt-controller at 17a00000 {
> + compatible = "arm,gic-v3";
> + reg = <0x17a00000 0x10000>, /* GICD */
> + <0x17b00000 0x100000>; /* GICR * 8 */
> + #interrupt-cells = <3>;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges;
> + interrupt-controller;
> + #redistributor-regions = <1>;
> + redistributor-stride = <0x0 0x20000>;
Is this needed? The redistributor stuff can be left out if there's only
one right?
> + interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
> + };
> +
> + blsp2_uart1: serial at c1b0000 {
Clk name says uart2 though?
> + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
> + reg = <0xc1b0000 0x1000>;
> + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&gcc GCC_BLSP2_UART2_APPS_CLK>,
> + <&gcc GCC_BLSP2_AHB_CLK>;
> + clock-names = "core", "iface";
> + status = "disabled";
> + };
> +
^ permalink raw reply
* [PATCH v2 2/2] arm64: dts: qcom: msm8998: Add rpm and regulators for MTP
From: Stephen Boyd @ 2018-05-07 23:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180428054248.22387-2-bjorn.andersson@linaro.org>
Quoting Bjorn Andersson (2018-04-27 22:42:48)
> diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> index d6665e4f801f..ccbf6347aacb 100644
> --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> @@ -220,6 +220,16 @@
> method = "smc";
> };
>
> + rpm_glink: rpm-glink {
> + compatible = "qcom,glink-rpm";
> +
> + interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
> +
> + qcom,rpm-msg-ram = <&rpm_msg_ram>;
> +
> + mboxes = <&apcs_glb 0>;
Why so many newlines?
> + };
> +
> soc: soc {};
> };
>
> @@ -337,4 +347,77 @@
> #interrupt-cells = <4>;
> cell-index = <0>;
> };
> +
> + rpm_msg_ram: memory at 68000 {
unit address doesn't match reg property.
> + compatible = "qcom,rpm-msg-ram";
> + reg = <0x778000 0x7000>;
> + };
> +
> + apcs_glb: mailbox at 9820000 {
unit address doesn't match reg property.
> + compatible = "qcom,msm8998-apcs-hmss-global";
> + reg = <0x17911000 0x1000>;
> +
> + #mbox-cells = <1>;
> + };
> +};
> +
> +&rpm_glink {
> + rpm_requests {
> + compatible = "qcom,rpm-msm8998";
> + qcom,glink-channels = "rpm_requests";
> +
> + pm8998-regulators {
> + compatible = "qcom,rpm-pm8998-regulators";
> +
> + pm8998_s1: s1 {};
> + pm8998_s2: s2 {};
> + pm8998_s3: s3 {};
> + pm8998_s4: s4 {};
> + pm8998_s5: s5 {};
> + pm8998_s6: s6 {};
> + pm8998_s7: s7 {};
> + pm8998_s8: s8 {};
> + pm8998_s9: s9 {};
> + pm8998_s10: s10 {};
> + pm8998_s11: s11 {};
> + pm8998_s12: s12 {};
> + pm8998_s13: s13 {};
> + pm8998_l1: l1 {};
> + pm8998_l2: l2 {};
> + pm8998_l3: l3 {};
> + pm8998_l4: l4 {};
> + pm8998_l5: l5 {};
> + pm8998_l6: l6 {};
> + pm8998_l7: l7 {};
> + pm8998_l8: l8 {};
> + pm8998_l9: l9 {};
> + pm8998_l10: l10 {};
> + pm8998_l11: l11 {};
> + pm8998_l12: l12 {};
> + pm8998_l13: l13 {};
> + pm8998_l14: l14 {};
> + pm8998_l15: l15 {};
> + pm8998_l16: l16 {};
> + pm8998_l17: l17 {};
> + pm8998_l18: l18 {};
> + pm8998_l19: l19 {};
> + pm8998_l20: l20 {};
> + pm8998_l21: l21 {};
> + pm8998_l22: l22 {};
> + pm8998_l23: l23 {};
> + pm8998_l24: l24 {};
> + pm8998_l25: l25 {};
> + pm8998_l26: l26 {};
> + pm8998_l27: l27 {};
> + pm8998_l28: l28 {};
> + pm8998_lvs1: lvs1 {};
> + pm8998_lvs2: lvs2 {};
What's the benefit to having the nodes here instead of in each board?
> + };
> +
> + pmi8998-regulators {
> + compatible = "qcom,rpm-pmi8998-regulators";
> +
> + pmi8998_bob: bob {};
> + };
These may be board specific? So each regulator container would need
status = "disabled" and then status = "okay" in the board file.
^ permalink raw reply
* [PATCH v2 0/5] crypto: Speck support
From: Eric Biggers @ 2018-05-07 23:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAEX_ruHoVRnBPazLhi6c+ps52yjb_SW=VfwxjiAW8izjvs24uQ@mail.gmail.com>
Hi Samuel,
On Thu, Apr 26, 2018 at 03:05:44AM +0100, Samuel Neves wrote:
> On Wed, Apr 25, 2018 at 8:49 PM, Eric Biggers <ebiggers@google.com> wrote:
> > I agree that my explanation should have been better, and should have considered
> > more crypto algorithms. The main difficulty is that we have extreme performance
> > requirements -- it needs to be 50 MB/s at the very least on even low-end ARM
> > devices like smartwatches. And even with the NEON-accelerated Speck128-XTS
> > performance exceeding that after much optimization, we've been getting a lot of
> > pushback as people want closer to 100 MB/s.
> >
>
> I couldn't find any NEON-capable ARMv7 chip below 800 MHz, so this
> would put the performance upper bound around 15 cycles per byte, with
> the comfortable number being ~7. That's indeed tough, though not
> impossible.
>
> >
> > That's why I also included Speck64-XTS in the patches, since it was
> > straightforward to include, and some devices may really need that last 20-30% of
> > performance for encryption to be feasible at all. (And when the choice is
> > between unencrypted and a 64-bit block cipher, used in a context where the
> > weakest points in the cryptosystem are actually elsewhere such as the user's
> > low-entropy PIN and the flash storage doing wear-leveling, I'd certainly take
> > the 64-bit block cipher.) So far we haven't had to use Speck64 though, and if
> > that continues to be the case I'd be fine with Speck64 being removed, leaving
> > just Speck128.
> >
>
> I would very much prefer that to be the case. As many of us know,
> "it's better than nothing" has been often used to justify other bad
> choices, like RC4, that end up preventing better ones from being
> adopted. At a time where we're trying to get rid of 64-bit ciphers in
> TLS, where data volumes per session are comparatively low, it would be
> unfortunate if the opposite starts happening on encryption at rest.
>
> >
> > Note that in practice, to have any chance at meeting the performance requirement
> > the cipher needed to be NEON accelerated. That made benchmarking really hard
> > and time-consuming, since to definitely know how an algorithm performs it can
> > take upwards of a week to implement a NEON version. It needs to be very well
> > optimized too, to compare the algorithms fairly -- e.g. with Speck I got a 20%
> > performance improvement on some CPUs just by changing the NEON instructions used
> > to implement the 8-bit rotates, an optimization that is not possible with
> > ciphers that don't use rotate amounts that are multiples of 8. (This was an
> > intentional design choice by the Speck designers; they do know what they're
> > doing, actually.)
> >
> > Thus, we had to be pretty aggressive about dropping algorithms from
> > consideration if there were preliminary indications that they wouldn't perform
> > well, or had too little cryptanalysis, or had other issues such as an unclear
> > patent situation. Threefish for example I did test the C implementation at
> > https://github.com/wernerd/Skein3Fish, but on ARM32 it was over 4 times slower
> > than my NEON implementation of Speck128/256-XTS. And I did not see a clear way
> > that it could be improved over 4x with NEON, if at all, so I did not take the
> > long time it would have taken to write an optimized NEON implementation to
> > benchmark it properly. Perhaps that was a mistake. But, time is not unlimited.
> >
>
> In my limited experience with NEON and 64-bit ARX, there's usually a
> ~2x speedup solely from NEON's native 64-bit operations on ARMv7-A.
> The extra speedup from encrypting 2 block in parallel is then
> somewhere between 1x and 2x, depending on various details. Getting
> near 4x might be feasible, but it is indeed time-consuming to get
> there.
>
> >
> > As for the wide-block mode using ChaCha20 and Poly1305, you'd have to ask Paul
> > Crowley to explain it properly, but briefly it's actually a pseudorandom
> > permutation over an arbitrarily-sized message. So with dm-crypt for example, it
> > would operate on a whole 512-byte sector, and if any bit of the 512-byte
> > plaintext is changed, then every bit in the 512-byte ciphertext would change
> > with 50% probability. To make this possible, the construction uses a polynomial
> > evalution in GF(2^130-5) as a universal hash function, similar to the Poly1305
> > mode.
> >
>
> Oh, OK, that sounds like something resembling Naor-Reingold or its
> relatives. That would work, but with 3 or 4 passes I guess it wouldn't
> be very fast.
>
> >
> > Using ChaCha20's underlying 512-bit permutation to build a tweakable block
> > cipher is an interesting idea. But maybe in my crypto-naivety, it is not
> > obvious to me how to do so. Do you have references to any relevant papers?
> > Remember that we strongly prefer a published cipher to a custom one -- even if
> > the core is reused, a mistake may be made in the way it is used. Thus,
> > similarly to Paul's wide-block mode, I'd be concerned that we'd have to
> > self-publish a new construction, then use it with no outside crypto review.
> > *Maybe* it would be straightforward enough to be okay, but to know I'd need to
> > see the details of how it would actually work.
> >
>
> This would be the 'tweakable Even-Mansour' construction and its
> variants. The variant I'm most familiar with would be MEM [1],
> focusing on software friendliness, but there is other provable
> security work in the same vein, including [3, 4, 5]. It's very similar
> to how the XEX mode turns a block cipher into a tweakable block
> cipher.
>
> In [1, 2] we used a 1024-bit permutation out of BLAKE2 instead of
> ChaCha20's, but everything translates easily from one to the other. We
> also included cheap masks for 512-bit permutations, just in case.
>
> [1] https://eprint.iacr.org/2015/999
> [2] https://github.com/MEM-AEAD/mem-aead
> [3] https://eprint.iacr.org/2015/539
> [4] https://eprint.iacr.org/2015/476
> [5] https://competitions.cr.yp.to/round2/minalpherv11.pdf
>
> >
> > But in the end, Speck seemed like the clear choice because it had multiple NEON
> > implementations available already which showed it could be implemented very
> > efficiently in NEON; it has over 70 cryptanalysis papers (far more than most
> > ciphers) yet the security margin is still similar to AES; it has no intellectual
> > property concerns; there is a paper clearly explaining the design decisions; it
> > is naturally resistant to timing attacks; it supports a 128-bit block size, so
> > it can be easily used in XTS mode; it supports the same key sizes as AES; and it
> > has a simple and understandable design with no "magic numbers" besides 8 and 3
> > (compare to an actual backdoored algorithm like Dual_EC_DRGB, which basically
> > had a public key embedded in the algorithm). Also as Paul mentioned he is
> > confident in the construction, and he has published cryptanalysis on Salsa20, so
> > his opinion is probably more significant than mine :-)
> >
> > But I will definitely take a closer look at SPARX and some of the other ciphers
> > you mentioned in case I missed something. I really do appreciate the
> > suggestions, by the way, and in any case we do need to be very well prepared to
> > justify our choices. I just hope that people can understand that we are
> > implementing real-world crypto which must operate under *very* tight performance
> > constraints on ARM processors, and it must be compatible with dm-crypt and
> > fscrypt with no room for ciphertext expansion. Thus, many algorithms which may
> > at first seem reasonable choices had to (unfortunately) be excluded.
> >
>
> I understand it is a tough choice, and it's unfortunate that many of
> the algorithms we have cater mostly to either the
> high-hardware-accelerated-end or the extremely low-end, without a lot
> of good options at the middle-end.
>
First, we're planning a publication which explains our choices in more detail,
so please treat this as some more preliminary notes.
To make sure we've exhausted as many alternatives as possible, I wrote NEON
implementations of all the block ciphers you suggested with the exception of
SKINNY (which looked very hardware-oriented and not efficient in software), as
well as some that others have suggested. (It was tough, but after doing a
couple, it got much easier...) The following shows the decryption performance
I'm getting on an ARMv7 platform. Encryption speeds were usually similar, but
in our use case we care much more about decryption, as that affects the most
critical metrics such as the time to launch applications.
ChaCha8-MEM: 183256 KB/s
ChaCha12-MEM: 134833 KB/s
Chaskey-LTS-XTS: 99097 KB/s
ChaCha20-MEM: 87875 KB/s
Speck64/128-XTS: 85332 KB/s
Speck128/128-XTS: 73404 KB/s
RC5-128/12/256-XTS: 69887 KB/s
Speck128/256-XTS: 69597 KB/s
RC5-64/12/128-XTS: 69267 KB/s
LEA-128-XTS: 67986 KB/s
CHAM128/128-XTS: 52982 KB/s
LEA-256-XTS: 50429 KB/s
Threefish-256: 48349 KB/s
RC6-XTS: 46855 KB/s
RC5-128/20/256-XTS: 44291 KB/s
RC5-64/20/128-XTS: 43924 KB/s
NOEKEON-XTS: 40705 KB/s
Sparx128/128-XTS: 39191 KB/s
XTEA-XTS: 38239 KB/s
AES-128-XTS: 25549 KB/s
AES-256-XTS: 18640 KB/s
Remember that for dm-crypt or fscrypt over flash storage and/or f2fs, a stream
cipher is insecure. Moreover, on these (low-end) devices the status quo is no
encryption, and we need every bit of performance available. Anything below
50 MB/s is definitely unacceptable. But even at that speed we get many
complaints, so in practice we need something faster. That means that the
algorithms close to 50 MB/s, such as Threefish, still aren't fast enough.
ChaCha-MEM (based roughly on your paper: https://eprint.iacr.org/2015/999), has
the best performance, especially if we allow for the 12 or 8-round variants. My
code for it is based roughly on the existing
arch/arm/crypto/chacha20-neon-core.S, but updated to support the inverse
permutation (on 4 blocks at a time, using all 16 NEON registers) and do the
masking required by MEM. However, ChaCha-MEM would be a pretty bleeding-edge
and customized construction, and Paul Crowley and I have concerns about its
security. The problem is that the MEM security proof assumes that the
underlying permutation has no more detectable structural properties than a
randomly selected permutation. However, the ChaCha permutation is known to have
certain symmetries, e.g. if the sixteen 32-bit words are (a, a, a, a, b, b, b,
b, c, c, c, c, d, d, d, d), then they always map to some (e, e, e, e, f, f, f,
f, g, g, g, g, h, h, h, h).
For the MEM mask generation, we can use the "expand 32-byte k" constant to break
the symmetry, like is done in the ChaCha stream cipher. However, that's not
possible for the inner application of the permutation. So, we'd be using the
ChaCha permutation in a manner in which it wasn't intended, and the security of
the ChaCha stream cipher wouldn't directly carry over. Granted, it's not
impossible that it would be secure, but at the present time it doesn't seem like
a good choice to actually field.
Chaskey-LTS is faster than Speck, but unfortunately it's not really a viable
option because it has only a 64-bit security level, due to its use of the
Even-Mansour construction with a 128-bit key. Of course, it would still be
better than nothing, but we prefer a cipher that has a security level in line
with what is accepted for modern crypto.
RC5 with the traditional 12 rounds is about as fast as Speck, but there is a
known differential attack on that number of rounds. So if we choose RC5 we'd
almost certainly have to use the 20-round variant, which is much slower.
That leaves LEA-128-XTS as the only other algorithm that might meet the
performance requirement, as it is only slightly slower than Speck128-XTS. It
may be the most viable alternative, but beyond the slight performance loss it
still has some disadvantages compared to Speck:
- Importantly, the LEA authors forgot to include test vectors, so I'm not yet
100% sure I implemented it correctly. (The Speck authors unfortunately didn't
make the endianness of their test vectors clear in their initial publication,
but at least they actually provided test vectors!)
- LEA has received some cryptanalysis, but not nearly as much as Speck.
- It took some very heavy optimization to get good LEA performance, much more
than I had to do for Speck. My final LEA code has separate code paths for
128-bit and 256-bit keys, and has reordered and preprocessed the round keys,
and reordered the operations. As a result, it's harder to see how it maps to
the original paper. In contrast, my Speck code is more straightforward and
maintainable.
- LEA-256 (256-bit key) is much slower than LEA-128 (128-bit key), as it has
33% more rounds. LEA-256 would not be fast enough, so we would have to use
LEA-128. In contrast, with Speck we can use Speck128/256 (256-bit key).
We're willing to accept a 128-bit security level, but 256-bit is preferable.
(I think the Speck designers took a more informed approach to setting
appropriate security margins for a lightweight cipher; it seems that other
designers often choose too few or too many rounds, especially as the key
length is varied.)
- LEA encryption is also a bit slower than decryption, while with Speck
encryption and decryption are almost exactly the same speed.
Note that like Speck, LEA doesn't appear to be approved by a standards
organization either; it's just specified in a research paper.
Thus, from a technical perspective, and given the current state of the art in
lightweight cryptography, currently Speck128-XTS seems to be the best choice for
the problem domain. It's unfortunate that there are so few good options and
that the field is so politicized, but it is what it is.
Still, we don't want to abandon HPolyC (Paul's new ChaCha and Poly1305-based
wide-block mode), and eventually we hope to offer it as an option as well. But
it's not yet published, and it's a more complex algorithm that is harder to
implement so I haven't yet had a chance to implement and benchmark it. And we
don't want to continue to leave users unprotected while we spend a long time
coming up with the perfect algorithm, or for hardware AES support to arrive to
all low-end CPUs when it's unclear if/when that will happen.
Again, we're planning a publication which will explain all this in more detail.
Thanks!
Eric
^ permalink raw reply
* [PATCH v2 1/2] arm64: dts: Add msm8998 SoC and MTP board support
From: Bjorn Andersson @ 2018-05-07 23:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <152573399648.138124.10341359049104453178@swboyd.mtv.corp.google.com>
On Mon 07 May 15:59 PDT 2018, Stephen Boyd wrote:
> Quoting Bjorn Andersson (2018-04-27 22:42:47)
> > diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > new file mode 100644
> > index 000000000000..d6665e4f801f
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > @@ -0,0 +1,340 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. */
> > +
> > +#include <dt-bindings/interrupt-controller/arm-gic.h>
> > +#include <dt-bindings/clock/qcom,gcc-msm8998.h>
> > +
> > +/ {
> > + model = "Qualcomm Technologies, Inc. MSM 8998";
> > +
> > + interrupt-parent = <&intc>;
> > +
> > + qcom,msm-id = <292 0x0>;
>
> No update to dtbtool?
>
This allows me to concatenate the dtb to the Image.gz and boot the
device. From my scripts I see that I tried to use dtbTool before
reverting to this...
[..]
> > + cpu-map {
> > + cluster0 {
> > + core0 {
> > + cpu = <&CPU0>;
> > + };
> > +
> > + core1 {
> > + cpu = <&CPU1>;
> > + };
> > +
> > + core2 {
> > + cpu = <&CPU2>;
> > + };
> > +
> > + core3 {
> > + cpu = <&CPU3>;
> > + };
> > + };
> > +
> > + cluster1 {
> > + core0 {
> > + cpu = <&CPU4>;
> > + };
> > +
> > + core1 {
> > + cpu = <&CPU5>;
> > + };
> > +
> > + core2 {
> > + cpu = <&CPU6>;
> > + };
> > +
> > + core3 {
> > + cpu = <&CPU7>;
> > + };
> > + };
> > + };
>
> I still wonder if this is accurate, but OK.
>
Afaict it matches downstream, not sure if I'm missing something?
[..]
> > + intc: interrupt-controller at 17a00000 {
> > + compatible = "arm,gic-v3";
> > + reg = <0x17a00000 0x10000>, /* GICD */
> > + <0x17b00000 0x100000>; /* GICR * 8 */
> > + #interrupt-cells = <3>;
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + ranges;
> > + interrupt-controller;
> > + #redistributor-regions = <1>;
> > + redistributor-stride = <0x0 0x20000>;
>
> Is this needed? The redistributor stuff can be left out if there's only
> one right?
>
#redistributor-regions is listed as optional if there's more than 1, the
stride is still needed.
Afaict the stride still needs to be specified, as it's different from
the default 64kb.
> > + interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
> > + };
> > +
> > + blsp2_uart1: serial at c1b0000 {
>
> Clk name says uart2 though?
>
That's because it's the wrong clock. Thanks!
> > + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
> > + reg = <0xc1b0000 0x1000>;
> > + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&gcc GCC_BLSP2_UART2_APPS_CLK>,
> > + <&gcc GCC_BLSP2_AHB_CLK>;
> > + clock-names = "core", "iface";
> > + status = "disabled";
> > + };
Regards,
Bjorn
^ permalink raw reply
* [PATCH v2 2/2] arm64: dts: qcom: msm8998: Add rpm and regulators for MTP
From: Bjorn Andersson @ 2018-05-07 23:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <152573424824.138124.9876892052732688689@swboyd.mtv.corp.google.com>
On Mon 07 May 16:04 PDT 2018, Stephen Boyd wrote:
> Quoting Bjorn Andersson (2018-04-27 22:42:48)
> > diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > index d6665e4f801f..ccbf6347aacb 100644
> > --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> > @@ -220,6 +220,16 @@
> > method = "smc";
> > };
> >
> > + rpm_glink: rpm-glink {
> > + compatible = "qcom,glink-rpm";
> > +
> > + interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
> > +
> > + qcom,rpm-msg-ram = <&rpm_msg_ram>;
> > +
> > + mboxes = <&apcs_glb 0>;
>
> Why so many newlines?
>
No particular reason...
> > + };
> > +
> > soc: soc {};
> > };
> >
> > @@ -337,4 +347,77 @@
> > #interrupt-cells = <4>;
> > cell-index = <0>;
> > };
> > +
> > + rpm_msg_ram: memory at 68000 {
>
> unit address doesn't match reg property.
>
Doh...
> > + compatible = "qcom,rpm-msg-ram";
> > + reg = <0x778000 0x7000>;
> > + };
[..]
> > +&rpm_glink {
> > + rpm_requests {
> > + compatible = "qcom,rpm-msm8998";
> > + qcom,glink-channels = "rpm_requests";
> > +
> > + pm8998-regulators {
> > + compatible = "qcom,rpm-pm8998-regulators";
> > +
> > + pm8998_s1: s1 {};
[..]
> > + pm8998_lvs2: lvs2 {};
>
> What's the benefit to having the nodes here instead of in each board?
>
That's how we've done it in the previous boards, but I had a discussion
regarding this with Doug the other day and agree that it might make
sense to just leave them out.
In particular Doug wanted to use labels based on names in the schematics
for his board...
> > + };
> > +
> > + pmi8998-regulators {
> > + compatible = "qcom,rpm-pmi8998-regulators";
> > +
> > + pmi8998_bob: bob {};
> > + };
>
> These may be board specific? So each regulator container would need
> status = "disabled" and then status = "okay" in the board file.
>
Right, we haven't really seen the need for this before, but it seems to
make more sense to move all regulators and their references to the board
file.
Regards,
Bjorn
^ permalink raw reply
* [PATCH v2 1/2] dt-bindings: add MediaTek XS-PHY binding
From: Chunfeng Yun @ 2018-05-08 1:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507170435.GA14540@rob-hp-laptop>
On Mon, 2018-05-07 at 12:04 -0500, Rob Herring wrote:
> On Sat, May 05, 2018 at 10:15:05AM +0800, Chunfeng Yun wrote:
> > Add a DT binding documentation of XS-PHY for MediaTek SoCs
> > with USB3.1 GEN2 controller
> >
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> > ---
> > .../devicetree/bindings/phy/phy-mtk-xsphy.txt | 110 ++++++++++++++++++++
> > 1 file changed, 110 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/phy/phy-mtk-xsphy.txt
> >
> > diff --git a/Documentation/devicetree/bindings/phy/phy-mtk-xsphy.txt b/Documentation/devicetree/bindings/phy/phy-mtk-xsphy.txt
> > new file mode 100644
> > index 0000000..9a95fab
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/phy/phy-mtk-xsphy.txt
> > @@ -0,0 +1,110 @@
> > +MediaTek XS-PHY binding
> > +--------------------------
> > +
> > +The XS-PHY controller supports physical layer functionality for USB3.1
> > +GEN2 controller on MediaTek SoCs.
> > +
> > +Required properties (controller (parent) node):
> > + - compatible : should be "mediatek,<soc-model>-xsphy", "mediatek,xsphy",
> > + soc-model is the name of SoC, such as mt2712 etc;
> > + when using "mediatek,xsphy" compatible string, you need SoC specific
> > + ones in addition, one of:
> > + - "mediatek,mt3611-xsphy"
>
> What about mt2712 you mention above?
Sorry, forgot to modify it
^ permalink raw reply
* [RESEND PATCH] pinctrl: rockchip: Disable interrupt when changing it's capability
From: JeffyChen @ 2018-05-08 1:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507221511.GA6448@rodete-desktop-imager.corp.google.com>
Hi Brian,
On 05/08/2018 06:15 AM, Brian Norris wrote:
> + Doug
>
> Hi Jeffy,
>
> On Thu, May 03, 2018 at 02:55:53PM +0800, Jeffy Chen wrote:
>> We saw spurious irq when changing irq's trigger type, for example
>> setting gpio-keys's wakeup irq trigger type.
>>
>> And according to the TRM:
>> "Programming the GPIO registers for interrupt capability, edge-sensitive
>> or level-sensitive interrupts, and interrupt polarity should be
>> completed prior to enabling the interrupts on Port A in order to prevent
>> spurious glitches on the interrupt lines to the interrupt controller."
>>
>> Reported-by: Brian Norris <briannorris@google.com>
>> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
>> ---
>>
>> drivers/pinctrl/pinctrl-rockchip.c | 10 ++++++++++
>> 1 file changed, 10 insertions(+)
>>
>> diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
>> index 3924779f55785..7ff45ec8330d1 100644
>> --- a/drivers/pinctrl/pinctrl-rockchip.c
>> +++ b/drivers/pinctrl/pinctrl-rockchip.c
>> @@ -2727,9 +2727,19 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
>> return -EINVAL;
>> }
>>
>> + /**
>
> The typical multiline comment style is to use only 1 asterisk -- 2
> asterisks usually denote something more formal, like kerneldoc.
ok, will fix it.
>
>> + * According to the TRM, we should keep irq disabled during programming
>> + * interrupt capability to prevent spurious glitches on the interrupt
>> + * lines to the interrupt controller.
>> + */
>
> It's also worth noting that this case may come up in
> rockchip_irq_demux() for EDGE_BOTH triggers:
>
> /*
> * Triggering IRQ on both rising and falling edge
> * needs manual intervention.
> */
> if (bank->toggle_edge_mode & BIT(irq)) {
> ...
> polarity = readl_relaxed(bank->reg_base +
> GPIO_INT_POLARITY);
> if (data & BIT(irq))
> polarity &= ~BIT(irq);
> else
> polarity |= BIT(irq);
> writel(polarity,
> bank->reg_base + GPIO_INT_POLARITY);
>
> AIUI, this case is not actually a problem, because this polarity
> reconfiguration happens before we call generic_handle_irq(), so the
> extra spurious interrupt is handled and cleared after this point. But it
> seems like this should be noted somewhere in either the commit message,
> the code comments, or both.
just from my testing, the spurious irq only happen when set EDGE_RISING
to a gpio which is already high level, or set EDGE_FALLING to a gpio
which is already low level.so the demux / EDGE_BOTH seem ok.
but adding comments as your suggested is a good idea, will do that.
>
> On the other hand...this also implies there may be a race condition
> there, where we might lose an interrupt if there is an edge between the
> re-configuration of the polarity in rockchip_irq_demux() and the
> clearing/handling of the interrupt (handle_edge_irq() ->
> chip->irq_ack()). If we have an edge between there, then we might ack
> it, but leave the polarity such that we aren't ready for the next
> (inverted) edge.
if let me guess, the unexpected irq we saw is the hardware trying to
avoid losing irq? for example, we set a EDGE_RISING, and the hardware
saw the gpio is already high, then though it might lost an irq, so fake
one for safe?
i'll try to confirm it with IC guys.
>
> I'm not 100% sure about the above, so it might be good to verify it. But
> I also expect this means there's really no way to 100% reliably
> implement both-edge trigger types on hardware like this that doesn't
> directly implement it. So I'm not sure what we'd do with that knowledge.
>
>> + data = readl(bank->reg_base + GPIO_INTEN);
>> + writel_relaxed(data & ~mask, gc->reg_base + GPIO_INTEN);
>
> Not sure if this is a needless optimization: but couldn't you only
> disable the interrupt (and make the level and polarity changes) only if
> the level or polarity are actually changing? For example, it's possible
> to end up here when changing from EDGE_BOTH to EDGE_RISING, but we might
> not actually program a new value.
right, i noticed that too, will add a patch for that in v2.
>
> Brian
>
>> +
>> writel_relaxed(level, gc->reg_base + GPIO_INTTYPE_LEVEL);
>> writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY);
>>
>> + writel_relaxed(data, gc->reg_base + GPIO_INTEN);
>> +
>> irq_gc_unlock(gc);
>> raw_spin_unlock_irqrestore(&bank->slock, flags);
>> clk_disable(bank->clk);
>> --
>> 2.11.0
>>
>>
>
>
>
^ permalink raw reply
* [PATCH v3 1/3] clocksource: timer-ti-dm: remove the early platform driver registration
From: Daniel Lezcano @ 2018-05-08 1:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180504132731.14574-2-brgl@bgdev.pl>
On Fri, May 04, 2018 at 03:27:29PM +0200, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> This driver is no longer used as an early platform driver. Remove the
> registration macro.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
--
<http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* [RESEND PATCH] pinctrl: rockchip: Disable interrupt when changing it's capability
From: Brian Norris @ 2018-05-08 1:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5AF0FF18.1050905@rock-chips.com>
On Tue, May 08, 2018 at 09:36:24AM +0800, Jeffy Chen wrote:
> On 05/08/2018 06:15 AM, Brian Norris wrote:
> > On the other hand...this also implies there may be a race condition
> > there, where we might lose an interrupt if there is an edge between the
> > re-configuration of the polarity in rockchip_irq_demux() and the
> > clearing/handling of the interrupt (handle_edge_irq() ->
> > chip->irq_ack()). If we have an edge between there, then we might ack
> > it, but leave the polarity such that we aren't ready for the next
> > (inverted) edge.
>
> if let me guess, the unexpected irq we saw is the hardware trying to avoid
> losing irq? for example, we set a EDGE_RISING, and the hardware saw the gpio
> is already high, then though it might lost an irq, so fake one for safe?
I won't pretend to know what the IC designers were doing, but I don't
think that would resolve the problem I'm talking about. The sequence is
something like:
1. EDGE_BOTH IRQ occurs (e.g., low to high)
2. reconfigure polarity in rockchip_irq_demux() (polarity=low)
3. continue to handle_edge_irq()
4. another HW edge occurs (e.g., high to low)
5. handle_edge_irq() (from 3) acks (clears) IRQ (before a subsequent
rockchip_irq_demux() gets a chance to run and flip the polarity)
...
Now the polarity is still low, but the next trigger should be a
low-to-high edge.
> i'll try to confirm it with IC guys.
Brian
^ permalink raw reply
* [PATCH 0/7] drm/mediatek: support hdmi output for mt2701 and mt7623
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
Bibby Hsieh (3):
drm/mediatek: implement connection from BLS to DPI0
drm/mediatek: add a error return value when clock driver has been
prepared
drm/mediatek: config component output by device node port
chunhui dai (4):
drm/mediatek: move dpi private data to device
drm/mediatek: fix to get right bridge for dpi encoder
drm/mediatek: add dpi driver for mt2701 and mt7623
drm/mediatek: add hdmi driver for different hardware
drivers/gpu/drm/mediatek/Makefile | 4 +-
drivers/gpu/drm/mediatek/mtk_dpi.c | 125 +++++++---
drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 2 +-
drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 14 +-
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 +-
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 38 ++-
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 4 +-
drivers/gpu/drm/mediatek/mtk_hdmi.c | 88 +++++--
drivers/gpu/drm/mediatek/mtk_hdmi.h | 28 +++
drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 157 +++++++++++++
drivers/gpu/drm/mediatek/mtk_hdmi_regs.h | 1 +
drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 307 +++++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 129 +----------
13 files changed, 716 insertions(+), 183 deletions(-)
create mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
create mode 100644 drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c
--
2.12.5
^ permalink raw reply
* [PATCH 1/7] drm/mediatek: move dpi private data to device
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
From: chunhui dai <chunhui.dai@mediatek.com>
move colck factor and edge enable setting to private data.
Signed-off-by: chunhui dai <chunhui.dai@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 80 ++++++++++++++++++++++++++-------
drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 2 +-
2 files changed, 65 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index e80a603e5fb0..0a44ab175422 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -71,11 +71,13 @@ struct mtk_dpi {
struct clk *tvd_clk;
int irq;
struct drm_display_mode mode;
+ const struct mtk_dpi_conf *conf;
enum mtk_dpi_out_color_format color_format;
enum mtk_dpi_out_yc_map yc_map;
enum mtk_dpi_out_bit_num bit_num;
enum mtk_dpi_out_channel_swap channel_swap;
bool power_sta;
+ int refcount;
u8 power_ctl;
};
@@ -115,6 +117,12 @@ struct mtk_dpi_yc_limit {
u16 c_bottom;
};
+struct mtk_dpi_conf {
+ unsigned int (*cal_factor)(int clock);
+ const u32 reg_h_fre_con;
+ bool edge_sel_en;
+};
+
static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
{
u32 tmp = readl(dpi->regs + offset) & ~mask;
@@ -340,7 +348,13 @@ static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable)
static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi)
{
- mtk_dpi_mask(dpi, DPI_H_FRE_CON, H_FRE_2N, H_FRE_2N);
+ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N);
+}
+
+static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi)
+{
+ if (dpi->conf->edge_sel_en)
+ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN);
}
static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
@@ -368,6 +382,12 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
{
+ if (WARN_ON(dpi->refcount == 0))
+ return;
+
+ if (--dpi->refcount != 0)
+ return;
+
dpi->power_ctl &= ~pctl;
if ((dpi->power_ctl & DPI_POWER_START) ||
@@ -387,14 +407,17 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
{
int ret;
+ if (++dpi->refcount != 1)
+ return 0;
+
dpi->power_ctl |= pctl;
if (!(dpi->power_ctl & DPI_POWER_START) &&
!(dpi->power_ctl & DPI_POWER_ENABLE))
- return 0;
+ goto err_refcount;
if (dpi->power_sta)
- return 0;
+ goto err_refcount;
ret = clk_prepare_enable(dpi->engine_clk);
if (ret) {
@@ -416,6 +439,8 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
clk_disable_unprepare(dpi->engine_clk);
err_eng:
dpi->power_ctl &= ~pctl;
+err_refcount:
+ dpi->refcount--;
return ret;
}
@@ -433,16 +458,13 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
unsigned long pll_rate;
unsigned int factor;
+ if (!dpi) {
+ dev_err(dpi->dev, "invalid argument\n");
+ return -EINVAL;
+ }
/* let pll_rate can fix the valid range of tvdpll (1G~2GHz) */
pix_rate = 1000UL * mode->clock;
- if (mode->clock <= 27000)
- factor = 16 * 3;
- else if (mode->clock <= 84000)
- factor = 8 * 3;
- else if (mode->clock <= 167000)
- factor = 4 * 3;
- else
- factor = 2 * 3;
+ factor = dpi->conf->cal_factor(mode->clock);
pll_rate = pix_rate * factor;
dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
@@ -518,6 +540,7 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
mtk_dpi_config_yc_map(dpi, dpi->yc_map);
mtk_dpi_config_color_format(dpi, dpi->color_format);
mtk_dpi_config_2n_h_fre(dpi);
+ mtk_dpi_config_disable_edge(dpi);
mtk_dpi_sw_reset(dpi, false);
return 0;
@@ -656,6 +679,31 @@ static const struct component_ops mtk_dpi_component_ops = {
.unbind = mtk_dpi_unbind,
};
+static unsigned int mt8173_calculate_factor(int clock)
+{
+ if (clock <= 27000)
+ return 16 * 3;
+ else if (clock <= 74250)
+ return 8 * 3;
+ else if (clock <= 167000)
+ return 4 * 3;
+ else
+ return 2 * 3;
+}
+
+static const struct mtk_dpi_conf mt8173_conf = {
+ .cal_factor = mt8173_calculate_factor,
+ .reg_h_fre_con = 0xe0,
+};
+
+static const struct of_device_id mtk_dpi_of_ids[] = {
+ { .compatible = "mediatek,mt8173-dpi",
+ .data = &mt8173_conf,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mtk_dpi_of_ids);
+
static int mtk_dpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -663,13 +711,18 @@ static int mtk_dpi_probe(struct platform_device *pdev)
struct resource *mem;
struct device_node *bridge_node;
int comp_id;
+ const struct of_device_id *match;
int ret;
+ match = of_match_node(mtk_dpi_of_ids, dev->of_node);
+ if (!match)
+ return -ENODEV;
dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
if (!dpi)
return -ENOMEM;
dpi->dev = dev;
+ dpi->conf = (struct mtk_dpi_conf *)match->data;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dpi->regs = devm_ioremap_resource(dev, mem);
@@ -748,11 +801,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id mtk_dpi_of_ids[] = {
- { .compatible = "mediatek,mt8173-dpi", },
- {}
-};
-
struct platform_driver mtk_dpi_driver = {
.probe = mtk_dpi_probe,
.remove = mtk_dpi_remove,
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
index 4b6ad4751a31..d9db8c4cacd7 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
@@ -223,6 +223,6 @@
#define ESAV_CODE2 (0xFFF << 0)
#define ESAV_CODE3_MSB BIT(16)
-#define DPI_H_FRE_CON 0xE0
+#define EDGE_SEL_EN BIT(5)
#define H_FRE_2N BIT(25)
#endif /* __MTK_DPI_REGS_H */
--
2.12.5
^ permalink raw reply related
* [PATCH 2/7] drm/mediatek: fix to get right bridge for dpi encoder
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
From: chunhui dai <chunhui.dai@mediatek.com>
1, dpi is an encoder, there is an bridge in the struct
of decoder, we could use it.
2, using of_graph_get_remote_port_parent to get right
bridge in device tree.
Signed-off-by: chunhui dai <chunhui.dai@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 0a44ab175422..2b8b34c72697 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -63,7 +63,6 @@ enum mtk_dpi_out_color_format {
struct mtk_dpi {
struct mtk_ddp_comp ddp_comp;
struct drm_encoder encoder;
- struct drm_bridge *bridge;
void __iomem *regs;
struct device *dev;
struct clk *engine_clk;
@@ -643,8 +642,8 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
/* Currently DPI0 is fixed to be driven by OVL1 */
dpi->encoder.possible_crtcs = BIT(1);
-
- ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
+ dpi->encoder.bridge->encoder = &dpi->encoder;
+ ret = drm_bridge_attach(&dpi->encoder, dpi->encoder.bridge, NULL);
if (ret) {
dev_err(dev, "Failed to attach bridge: %d\n", ret);
goto err_cleanup;
@@ -709,7 +708,7 @@ static int mtk_dpi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mtk_dpi *dpi;
struct resource *mem;
- struct device_node *bridge_node;
+ struct device_node *ep, *bridge_node;
int comp_id;
const struct of_device_id *match;
int ret;
@@ -759,15 +758,21 @@ static int mtk_dpi_probe(struct platform_device *pdev)
return -EINVAL;
}
- bridge_node = of_graph_get_remote_node(dev->of_node, 0, 0);
- if (!bridge_node)
+ ep = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (ep) {
+ bridge_node = of_graph_get_remote_port_parent(ep);
+ of_node_put(ep);
+ }
+ if (!bridge_node) {
+ dev_err(dev, "Failed to find bridge node\n");
return -ENODEV;
+ }
dev_info(dev, "Found bridge node: %pOF\n", bridge_node);
- dpi->bridge = of_drm_find_bridge(bridge_node);
+ dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
of_node_put(bridge_node);
- if (!dpi->bridge)
+ if (!dpi->encoder.bridge)
return -EPROBE_DEFER;
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
--
2.12.5
^ permalink raw reply related
* [PATCH 3/7] drm/mediatek: add dpi driver for mt2701 and mt7623
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
From: chunhui dai <chunhui.dai@mediatek.com>
This patch adds dpi dirver suppot for both mt2701 and mt7623.
And also support other (existing or future) chips that use
the same binding and driver.
Signed-off-by: chunhui dai <chunhui.dai@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 24 ++++++++++++++++++++++--
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 +
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 2b8b34c72697..e1af1d0d213d 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -640,8 +640,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
}
drm_encoder_helper_add(&dpi->encoder, &mtk_dpi_encoder_helper_funcs);
- /* Currently DPI0 is fixed to be driven by OVL1 */
- dpi->encoder.possible_crtcs = BIT(1);
+ dpi->encoder.possible_crtcs = BIT(0) | BIT(1);
dpi->encoder.bridge->encoder = &dpi->encoder;
ret = drm_bridge_attach(&dpi->encoder, dpi->encoder.bridge, NULL);
if (ret) {
@@ -690,12 +689,33 @@ static unsigned int mt8173_calculate_factor(int clock)
return 2 * 3;
}
+static unsigned int mt2701_calculate_factor(int clock)
+{
+ if (clock <= 64000)
+ return 16;
+ else if (clock <= 128000)
+ return 8;
+ else if (clock <= 256000)
+ return 4;
+ else
+ return 2;
+}
+
static const struct mtk_dpi_conf mt8173_conf = {
.cal_factor = mt8173_calculate_factor,
.reg_h_fre_con = 0xe0,
};
+static const struct mtk_dpi_conf mt2701_conf = {
+ .cal_factor = mt2701_calculate_factor,
+ .reg_h_fre_con = 0xb0,
+ .edge_sel_en = true,
+};
+
static const struct of_device_id mtk_dpi_of_ids[] = {
+ { .compatible = "mediatek,mt2701-dpi",
+ .data = &mt2701_conf,
+ },
{ .compatible = "mediatek,mt8173-dpi",
.data = &mt8173_conf,
},
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index a2ca90fc403c..f4fb86ab7b8d 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -372,6 +372,7 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
{ .compatible = "mediatek,mt8173-disp-ufoe", .data = (void *)MTK_DISP_UFOE },
{ .compatible = "mediatek,mt2701-dsi", .data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8173-dsi", .data = (void *)MTK_DSI },
+ { .compatible = "mediatek,mt2701-dpi", .data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8173-dpi", .data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
--
2.12.5
^ permalink raw reply related
* [PATCH 4/7] drm/mediatek: add hdmi driver for different hardware
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
From: chunhui dai <chunhui.dai@mediatek.com>
This patch adds hdmi dirver suppot for both MT2701 and MT7623.
And also support other (existing or future) chips that use
the same binding and driver.
Signed-off-by: Chunhui Dai <chunhui.dai@mediatek.com>
---
drivers/gpu/drm/mediatek/Makefile | 4 +-
drivers/gpu/drm/mediatek/mtk_hdmi.c | 88 +++++--
drivers/gpu/drm/mediatek/mtk_hdmi.h | 28 +++
drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 157 +++++++++++++
drivers/gpu/drm/mediatek/mtk_hdmi_regs.h | 1 +
drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 307 +++++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 129 +----------
7 files changed, 566 insertions(+), 148 deletions(-)
create mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
create mode 100644 drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index ce83c396a742..44464893c1cb 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
mediatek-drm-hdmi-objs := mtk_cec.o \
mtk_hdmi.o \
mtk_hdmi_ddc.o \
- mtk_mt8173_hdmi_phy.o
+ mtk_mt2701_hdmi_phy.o \
+ mtk_mt8173_hdmi_phy.o \
+ mtk_hdmi_phy.o
obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 59a11026dceb..accafd95d6a8 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -233,6 +233,7 @@ static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black)
static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable)
{
struct arm_smccc_res res;
+ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(hdmi->phy);
/*
* MT8173 HDMI hardware has an output control bit to enable/disable HDMI
@@ -240,8 +241,13 @@ static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable)
* The ARM trusted firmware provides an API for the HDMI driver to set
* this control bit to enable HDMI output in supervisor mode.
*/
- arm_smccc_smc(MTK_SIP_SET_AUTHORIZED_SECURE_REG, 0x14000904, 0x80000000,
- 0, 0, 0, 0, 0, &res);
+ if (hdmi_phy->conf && hdmi_phy->conf->tz_enabled)
+ arm_smccc_smc(MTK_SIP_SET_AUTHORIZED_SECURE_REG, 0x14000904,
+ 0x80000000, 0, 0, 0, 0, 0, &res);
+ else
+ regmap_update_bits(hdmi->sys_regmap,
+ hdmi->sys_offset + HDMI_SYS_CFG20,
+ HDMI_PSECUR_EN, enable ? 0 : HDMI_PSECUR_EN);
regmap_update_bits(hdmi->sys_regmap, hdmi->sys_offset + HDMI_SYS_CFG20,
HDMI_PCLK_FREE_RUN, enable ? HDMI_PCLK_FREE_RUN : 0);
@@ -1437,6 +1443,7 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
struct platform_device *cec_pdev;
struct regmap *regmap;
struct resource *mem;
+ const char *phy_name;
int ret;
ret = mtk_hdmi_get_all_clk(hdmi, np);
@@ -1445,9 +1452,20 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
return ret;
}
+ ret = of_property_read_string(np, "phy-names", &phy_name);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read phy-names: %d\n", ret);
+ return ret;
+ }
+ hdmi->phy = devm_phy_get(dev, phy_name);
+ if (IS_ERR(hdmi->phy)) {
+ ret = PTR_ERR(hdmi->phy);
+ dev_err(dev, "Failed to get HDMI PHY: %d\n", ret);
+ return ret;
+ }
+
/* The CEC module handles HDMI hotplug detection */
- cec_np = of_find_compatible_node(np->parent, NULL,
- "mediatek,mt8173-cec");
+ cec_np = of_parse_phandle(np, "cec", 0);
if (!cec_np) {
dev_err(dev, "Failed to find CEC node\n");
return -EINVAL;
@@ -1486,8 +1504,14 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
return PTR_ERR(hdmi->regs);
remote = of_graph_get_remote_node(np, 1, 0);
- if (!remote)
- return -EINVAL;
+ if (!remote) {
+ i2c_np = of_parse_phandle(np, "ddc-i2c-bus", 0);
+ if (!i2c_np) {
+ dev_err(dev, "Failed to find ddc-i2c-bus node\n");
+ return -EINVAL;
+ }
+ goto find_ddc_adpt;
+ }
if (!of_device_is_compatible(remote, "hdmi-connector")) {
hdmi->next_bridge = of_drm_find_bridge(remote);
@@ -1507,6 +1531,7 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
}
of_node_put(remote);
+find_ddc_adpt:
hdmi->ddc_adpt = of_find_i2c_adapter_by_node(i2c_np);
if (!hdmi->ddc_adpt) {
dev_err(dev, "Failed to get ddc i2c adapter by node\n");
@@ -1575,6 +1600,11 @@ static int mtk_hdmi_audio_hw_params(struct device *dev, void *data,
hdmi_params.aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
hdmi_params.aud_mclk = HDMI_AUD_MCLK_128FS;
break;
+ case HDMI_SPDIF:
+ hdmi_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
+ hdmi_params.aud_sampe_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+ hdmi_params.aud_input_type = HDMI_AUD_INPUT_SPDIF;
+ break;
default:
dev_err(hdmi->dev, "%s: Invalid DAI format %d\n", __func__,
daifmt->fmt);
@@ -1650,15 +1680,15 @@ static void mtk_hdmi_register_audio_driver(struct device *dev)
.max_i2s_channels = 2,
.i2s = 1,
};
- struct platform_device *pdev;
+ static struct platform_device *pdev;
- pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
- PLATFORM_DEVID_AUTO, &codec_data,
- sizeof(codec_data));
- if (IS_ERR(pdev))
+ if (!pdev) {
+ pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_NONE, &codec_data,
+ sizeof(codec_data));
+ DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME);
+ }
return;
-
- DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME);
}
static int mtk_drm_hdmi_probe(struct platform_device *pdev)
@@ -1672,18 +1702,12 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
return -ENOMEM;
hdmi->dev = dev;
+ mtk_hdmi_register_audio_driver(dev);
ret = mtk_hdmi_dt_parse_pdata(hdmi, pdev);
if (ret)
return ret;
- hdmi->phy = devm_phy_get(dev, "hdmi");
- if (IS_ERR(hdmi->phy)) {
- ret = PTR_ERR(hdmi->phy);
- dev_err(dev, "Failed to get HDMI PHY: %d\n", ret);
- return ret;
- }
-
platform_set_drvdata(pdev, hdmi);
ret = mtk_hdmi_output_init(hdmi);
@@ -1692,8 +1716,6 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
return ret;
}
- mtk_hdmi_register_audio_driver(dev);
-
hdmi->bridge.funcs = &mtk_hdmi_bridge_funcs;
hdmi->bridge.of_node = pdev->dev.of_node;
drm_bridge_add(&hdmi->bridge);
@@ -1704,7 +1726,6 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
goto err_bridge_remove;
}
- dev_dbg(dev, "mediatek hdmi probe success\n");
return 0;
err_bridge_remove:
@@ -1773,8 +1794,25 @@ static struct platform_driver * const mtk_hdmi_drivers[] = {
static int __init mtk_hdmitx_init(void)
{
- return platform_register_drivers(mtk_hdmi_drivers,
- ARRAY_SIZE(mtk_hdmi_drivers));
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mtk_hdmi_drivers); i++) {
+ ret = platform_driver_register(mtk_hdmi_drivers[i]);
+ if (ret < 0) {
+ pr_err("Failed to register %s driver: %d\n",
+ mtk_hdmi_drivers[i]->driver.name, ret);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0)
+ platform_driver_unregister(mtk_hdmi_drivers[i]);
+
+ return ret;
}
static void __exit mtk_hdmitx_exit(void)
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.h b/drivers/gpu/drm/mediatek/mtk_hdmi.h
index 6371b3de1ff6..a4546b83329f 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.h
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.h
@@ -13,11 +13,39 @@
*/
#ifndef _MTK_HDMI_CTRL_H
#define _MTK_HDMI_CTRL_H
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+
+struct mtk_hdmi_phy_conf {
+ bool tz_enabled;
+ const struct clk_ops *hdmi_phy_clk_ops;
+ const struct phy_ops *hdmi_phy_dev_ops;
+};
+
+struct mtk_hdmi_phy {
+ void __iomem *regs;
+ struct device *dev;
+ struct mtk_hdmi_phy_conf *conf;
+ struct clk *pll;
+ struct clk_hw pll_hw;
+ unsigned long pll_rate;
+ unsigned char drv_imp_clk;
+ unsigned char drv_imp_d2;
+ unsigned char drv_imp_d1;
+ unsigned char drv_imp_d0;
+ unsigned int ibias;
+ unsigned int ibias_up;
+};
struct platform_driver;
extern struct platform_driver mtk_cec_driver;
extern struct platform_driver mtk_hdmi_ddc_driver;
extern struct platform_driver mtk_hdmi_phy_driver;
+extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf;
+extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf;
+
#endif /* _MTK_HDMI_CTRL_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
new file mode 100644
index 000000000000..325790abd469
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Jie Qiu <jie.qiu@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/phy/phy.h>
+#include "mtk_hdmi.h"
+
+static void mtk_hdmi_phy_clk_get_ops(struct mtk_hdmi_phy *hdmi_phy,
+ const struct clk_ops **ops)
+{
+ if (hdmi_phy && hdmi_phy->conf && hdmi_phy->conf->hdmi_phy_clk_ops)
+ *ops = hdmi_phy->conf->hdmi_phy_clk_ops;
+ else
+ dev_err(hdmi_phy->dev, "Failed to get clk ops of phy\n");
+}
+
+static const struct phy_ops *
+mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy)
+{
+ if (hdmi_phy && hdmi_phy->conf && hdmi_phy->conf->hdmi_phy_dev_ops)
+ return hdmi_phy->conf->hdmi_phy_dev_ops;
+ dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n");
+ return NULL;
+}
+
+static int mtk_hdmi_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_hdmi_phy *hdmi_phy;
+ struct resource *mem;
+ struct clk *ref_clk;
+ const char *ref_clk_name;
+ struct clk_init_data clk_init = {
+ .num_parents = 1,
+ .parent_names = (const char * const *)&ref_clk_name,
+ .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
+ };
+
+ struct phy *phy;
+ struct phy_provider *phy_provider;
+ int ret;
+
+ hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
+ if (!hdmi_phy)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hdmi_phy->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(hdmi_phy->regs)) {
+ ret = PTR_ERR(hdmi_phy->regs);
+ dev_err(dev, "Failed to get memory resource: %d\n", ret);
+ return ret;
+ }
+
+ ref_clk = devm_clk_get(dev, "pll_ref");
+ if (IS_ERR(ref_clk)) {
+ ret = PTR_ERR(ref_clk);
+ dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n",
+ ret);
+ return ret;
+ }
+ ref_clk_name = __clk_get_name(ref_clk);
+
+ ret = of_property_read_string(dev->of_node, "clock-output-names",
+ &clk_init.name);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read clock-output-names: %d\n", ret);
+ return ret;
+ }
+
+ hdmi_phy->dev = dev;
+ hdmi_phy->conf =
+ (struct mtk_hdmi_phy_conf *)of_device_get_match_data(dev);
+ mtk_hdmi_phy_clk_get_ops(hdmi_phy, &clk_init.ops);
+ hdmi_phy->pll_hw.init = &clk_init;
+ hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
+ if (IS_ERR(hdmi_phy->pll)) {
+ ret = PTR_ERR(hdmi_phy->pll);
+ dev_err(dev, "Failed to register PLL: %d\n", ret);
+ return ret;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
+ &hdmi_phy->ibias);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret);
+ return ret;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
+ &hdmi_phy->ibias_up);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
+ hdmi_phy->drv_imp_clk = 0x30;
+ hdmi_phy->drv_imp_d2 = 0x30;
+ hdmi_phy->drv_imp_d1 = 0x30;
+ hdmi_phy->drv_imp_d0 = 0x30;
+
+ phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy));
+ if (IS_ERR(phy)) {
+ dev_err(dev, "Failed to create HDMI PHY\n");
+ return PTR_ERR(phy);
+ }
+ phy_set_drvdata(phy, hdmi_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider)) {
+ dev_err(dev, "Failed to register HDMI PHY\n");
+ return PTR_ERR(phy_provider);
+ }
+
+ return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
+ hdmi_phy->pll);
+}
+
+static int mtk_hdmi_phy_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id mtk_hdmi_phy_match[] = {
+ { .compatible = "mediatek,mt2701-hdmi-phy",
+ .data = &mtk_hdmi_phy_2701_conf,
+ },
+ { .compatible = "mediatek,mt8173-hdmi-phy",
+ .data = &mtk_hdmi_phy_8173_conf,
+ },
+ {},
+};
+
+struct platform_driver mtk_hdmi_phy_driver = {
+ .probe = mtk_hdmi_phy_probe,
+ .remove = mtk_hdmi_phy_remove,
+ .driver = {
+ .name = "mediatek-hdmi-phy",
+ .of_match_table = mtk_hdmi_phy_match,
+ },
+};
+
+MODULE_DESCRIPTION("MediaTek HDMI PHY Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_regs.h b/drivers/gpu/drm/mediatek/mtk_hdmi_regs.h
index a5cb07d12c9c..e53c6646571c 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_regs.h
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_regs.h
@@ -227,6 +227,7 @@
#define DEEP_COLOR_EN BIT(0)
#define HDMI_AUDIO_TEST_SEL BIT(8)
#define HDMI2P0_EN BIT(11)
+#define HDMI_PSECUR_EN BIT(15)
#define HDMI_OUT_FIFO_EN BIT(16)
#define HDMI_OUT_FIFO_CLK_INV BIT(17)
#define MHL_MODE_ON BIT(28)
diff --git a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c
new file mode 100644
index 000000000000..8af5e6c1aecc
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *Copyright (c) 2018 MediaTek Inc.
+ *Author: Chunhui Dai <chunhui.dai@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/phy/phy.h>
+#include "mtk_hdmi.h"
+
+#define HDMI_CON0 0x00
+#define RG_HDMITX_DRV_IBIAS (0)
+#define RG_HDMITX_DRV_IBIAS_MASK (0x3F << 0)
+#define RG_HDMITX_EN_SER (12)
+#define RG_HDMITX_EN_SER_MASK (0x0F << 12)
+#define RG_HDMITX_EN_SLDO (16)
+#define RG_HDMITX_EN_SLDO_MASK (0x0F << 16)
+#define RG_HDMITX_EN_PRED (20)
+#define RG_HDMITX_EN_PRED_MASK (0x0F << 20)
+#define RG_HDMITX_EN_IMP (24)
+#define RG_HDMITX_EN_IMP_MASK (0x0F << 24)
+#define RG_HDMITX_EN_DRV (28)
+#define RG_HDMITX_EN_DRV_MASK (0x0F << 28)
+
+#define HDMI_CON1 0x04
+#define RG_HDMITX_PRED_IBIAS (18)
+#define RG_HDMITX_PRED_IBIAS_MASK (0x0F << 18)
+#define RG_HDMITX_PRED_IMP (0x01 << 22)
+#define RG_HDMITX_DRV_IMP (26)
+#define RG_HDMITX_DRV_IMP_MASK (0x3F << 26)
+
+#define HDMI_CON2 0x08
+#define RG_HDMITX_EN_TX_CKLDO (0x01 << 0)
+#define RG_HDMITX_EN_TX_POSDIV (0x01 << 1)
+#define RG_HDMITX_TX_POSDIV (3)
+#define RG_HDMITX_TX_POSDIV_MASK (0x03 << 3)
+#define RG_HDMITX_EN_MBIAS (0x01 << 6)
+#define RG_HDMITX_MBIAS_LPF_EN (0x01 << 7)
+
+#define HDMI_CON4 0x10
+#define RG_HDMITX_RESERVE_MASK (0xFFFFFFFF << 0)
+
+#define HDMI_CON6 0x18
+#define RG_HTPLL_BR (0)
+#define RG_HTPLL_BR_MASK (0x03 << 0)
+#define RG_HTPLL_BC (2)
+#define RG_HTPLL_BC_MASK (0x03 << 2)
+#define RG_HTPLL_BP (4)
+#define RG_HTPLL_BP_MASK (0x0F << 4)
+#define RG_HTPLL_IR (8)
+#define RG_HTPLL_IR_MASK (0x0F << 8)
+#define RG_HTPLL_IC (12)
+#define RG_HTPLL_IC_MASK (0x0F << 12)
+#define RG_HTPLL_POSDIV (16)
+#define RG_HTPLL_POSDIV_MASK (0x03 << 16)
+#define RG_HTPLL_PREDIV (18)
+#define RG_HTPLL_PREDIV_MASK (0x03 << 18)
+#define RG_HTPLL_FBKSEL (20)
+#define RG_HTPLL_FBKSEL_MASK (0x03 << 20)
+#define RG_HTPLL_RLH_EN (0x01 << 22)
+#define RG_HTPLL_FBKDIV (24)
+#define RG_HTPLL_FBKDIV_MASK (0x7F << 24)
+#define RG_HTPLL_EN (0x01 << 31)
+
+#define HDMI_CON7 0x1c
+#define RG_HTPLL_AUTOK_EN (0x01 << 23)
+#define RG_HTPLL_DIVEN (28)
+#define RG_HTPLL_DIVEN_MASK (0x07 << 28)
+
+static inline struct mtk_hdmi_phy *to_mtk_hdmi_pll(struct clk_hw *hw)
+{
+ return container_of(hw, struct mtk_hdmi_phy, pll_hw);
+}
+
+static inline void mtk_hdmi_pll_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 tmp = readl(hdmi_phy->regs + offset) & ~mask;
+
+ tmp |= (val & mask);
+ writel(tmp, hdmi_phy->regs + offset);
+}
+
+static int mtk_hdmi_pll_enable(struct clk_hw *hw)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN,
+ RG_HTPLL_AUTOK_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_RLH_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x3 << RG_HTPLL_POSDIV),
+ RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS,
+ RG_HDMITX_EN_MBIAS);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, RG_HTPLL_EN, RG_HTPLL_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO,
+ RG_HDMITX_EN_TX_CKLDO);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_SLDO),
+ RG_HDMITX_EN_SLDO_MASK);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN,
+ RG_HDMITX_MBIAS_LPF_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV,
+ RG_HDMITX_EN_TX_POSDIV);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_SER),
+ RG_HDMITX_EN_SER_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_PRED),
+ RG_HDMITX_EN_PRED_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_DRV),
+ RG_HDMITX_EN_DRV_MASK);
+ usleep_range(80, 100);
+ return 0;
+}
+
+static void mtk_hdmi_pll_disable(struct clk_hw *hw)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_DRV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_PRED_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_SER_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_TX_POSDIV);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_MBIAS_LPF_EN);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_SLDO_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_TX_CKLDO);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_EN);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_MBIAS);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_RLH_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, 0, RG_HTPLL_AUTOK_EN);
+ usleep_range(80, 100);
+}
+
+static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+ u32 pos_div;
+
+ if (rate <= 64000000)
+ pos_div = 3;
+ else if (rate <= 12800000)
+ pos_div = 1;
+ else
+ pos_div = 1;
+
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x3 << RG_HTPLL_PREDIV),
+ RG_HTPLL_PREDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x3 << RG_HTPLL_POSDIV),
+ RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IC),
+ RG_HTPLL_IC_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IR),
+ RG_HTPLL_IR_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, (pos_div << RG_HDMITX_TX_POSDIV),
+ RG_HDMITX_TX_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (1 << RG_HTPLL_FBKSEL),
+ RG_HTPLL_FBKSEL_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (19 << RG_HTPLL_FBKDIV),
+ RG_HTPLL_FBKDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, (0x2 << RG_HTPLL_DIVEN),
+ RG_HTPLL_DIVEN_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0xc << RG_HTPLL_BP),
+ RG_HTPLL_BP_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x2 << RG_HTPLL_BC),
+ RG_HTPLL_BC_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_BR),
+ RG_HTPLL_BR_MASK);
+
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON1, 0, RG_HDMITX_PRED_IMP);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON1, (0x3 << RG_HDMITX_PRED_IBIAS),
+ RG_HDMITX_PRED_IBIAS_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0x0 << RG_HDMITX_EN_IMP),
+ RG_HDMITX_EN_IMP_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON1, (0x28 << RG_HDMITX_DRV_IMP),
+ RG_HDMITX_DRV_IMP_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON4, 0x28, RG_HDMITX_RESERVE_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xa << RG_HDMITX_DRV_IBIAS),
+ RG_HDMITX_DRV_IBIAS_MASK);
+ return 0;
+}
+
+static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+
+ hdmi_phy->pll_rate = rate;
+ return rate;
+}
+
+static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_pll(hw);
+
+ return hdmi_phy->pll_rate;
+}
+
+static const struct clk_ops mtk_hdmi_phy_pll_ops = {
+ .enable = mtk_hdmi_pll_enable,
+ .disable = mtk_hdmi_pll_disable,
+ .set_rate = mtk_hdmi_pll_set_rate,
+ .round_rate = mtk_hdmi_pll_round_rate,
+ .recalc_rate = mtk_hdmi_pll_recalc_rate,
+};
+
+static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy)
+{
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN,
+ RG_HTPLL_AUTOK_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_RLH_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, (0x3 << RG_HTPLL_POSDIV),
+ RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS,
+ RG_HDMITX_EN_MBIAS);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, RG_HTPLL_EN, RG_HTPLL_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO,
+ RG_HDMITX_EN_TX_CKLDO);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_SLDO),
+ RG_HDMITX_EN_SLDO_MASK);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN,
+ RG_HDMITX_MBIAS_LPF_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV,
+ RG_HDMITX_EN_TX_POSDIV);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_SER),
+ RG_HDMITX_EN_SER_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_PRED),
+ RG_HDMITX_EN_PRED_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, (0xf << RG_HDMITX_EN_DRV),
+ RG_HDMITX_EN_DRV_MASK);
+ usleep_range(80, 100);
+}
+
+static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy)
+{
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_DRV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_PRED_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_SER_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_TX_POSDIV);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_MBIAS_LPF_EN);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON0, 0, RG_HDMITX_EN_SLDO_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_TX_CKLDO);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_EN);
+ usleep_range(80, 100);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON2, 0, RG_HDMITX_EN_MBIAS);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_POSDIV_MASK);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON6, 0, RG_HTPLL_RLH_EN);
+ mtk_hdmi_pll_mask(hdmi_phy, HDMI_CON7, 0, RG_HTPLL_AUTOK_EN);
+ usleep_range(80, 100);
+}
+
+static int mtk_hdmi_phy_power_on(struct phy *phy)
+{
+ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+ int ret;
+
+ ret = clk_prepare_enable(hdmi_phy->pll);
+ if (ret < 0)
+ return ret;
+
+ mtk_hdmi_phy_enable_tmds(hdmi_phy);
+
+ return 0;
+}
+
+static int mtk_hdmi_phy_power_off(struct phy *phy)
+{
+ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ mtk_hdmi_phy_disable_tmds(hdmi_phy);
+ clk_disable_unprepare(hdmi_phy->pll);
+
+ return 0;
+}
+
+static const struct phy_ops mtk_hdmi_phy_dev_ops = {
+ .power_on = mtk_hdmi_phy_power_on,
+ .power_off = mtk_hdmi_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf = {
+ .tz_enabled = false,
+ .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops,
+ .hdmi_phy_dev_ops = &mtk_hdmi_phy_dev_ops,
+};
+
+MODULE_AUTHOR("Chunhui Dai <chunhui.dai@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek HDMI PHY Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
index 51cb9cfb6646..1a35fdd405d8 100644
--- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
+++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
@@ -21,6 +21,7 @@
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/types.h>
+#include "mtk_hdmi.h"
#define HDMI_CON0 0x00
#define RG_HDMITX_PLL_EN BIT(31)
@@ -123,20 +124,6 @@
#define RGS_HDMITX_5T1_EDG (0xf << 4)
#define RGS_HDMITX_PLUG_TST BIT(0)
-struct mtk_hdmi_phy {
- void __iomem *regs;
- struct device *dev;
- struct clk *pll;
- struct clk_hw pll_hw;
- unsigned long pll_rate;
- u8 drv_imp_clk;
- u8 drv_imp_d2;
- u8 drv_imp_d1;
- u8 drv_imp_d0;
- u32 ibias;
- u32 ibias_up;
-};
-
static const u8 PREDIV[3][4] = {
{0x0, 0x0, 0x0, 0x0}, /* 27Mhz */
{0x1, 0x1, 0x1, 0x1}, /* 74Mhz */
@@ -367,7 +354,7 @@ static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
return hdmi_phy->pll_rate;
}
-static const struct clk_ops mtk_hdmi_pll_ops = {
+static const struct clk_ops mtk_hdmi_phy_pll_ops = {
.prepare = mtk_hdmi_pll_prepare,
.unprepare = mtk_hdmi_pll_unprepare,
.set_rate = mtk_hdmi_pll_set_rate,
@@ -414,118 +401,16 @@ static int mtk_hdmi_phy_power_off(struct phy *phy)
return 0;
}
-static const struct phy_ops mtk_hdmi_phy_ops = {
+static const struct phy_ops mtk_hdmi_phy_dev_ops = {
.power_on = mtk_hdmi_phy_power_on,
.power_off = mtk_hdmi_phy_power_off,
.owner = THIS_MODULE,
};
-static int mtk_hdmi_phy_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mtk_hdmi_phy *hdmi_phy;
- struct resource *mem;
- struct clk *ref_clk;
- const char *ref_clk_name;
- struct clk_init_data clk_init = {
- .ops = &mtk_hdmi_pll_ops,
- .num_parents = 1,
- .parent_names = (const char * const *)&ref_clk_name,
- .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
- };
- struct phy *phy;
- struct phy_provider *phy_provider;
- int ret;
-
- hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
- if (!hdmi_phy)
- return -ENOMEM;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi_phy->regs = devm_ioremap_resource(dev, mem);
- if (IS_ERR(hdmi_phy->regs)) {
- ret = PTR_ERR(hdmi_phy->regs);
- dev_err(dev, "Failed to get memory resource: %d\n", ret);
- return ret;
- }
-
- ref_clk = devm_clk_get(dev, "pll_ref");
- if (IS_ERR(ref_clk)) {
- ret = PTR_ERR(ref_clk);
- dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n",
- ret);
- return ret;
- }
- ref_clk_name = __clk_get_name(ref_clk);
-
- ret = of_property_read_string(dev->of_node, "clock-output-names",
- &clk_init.name);
- if (ret < 0) {
- dev_err(dev, "Failed to read clock-output-names: %d\n", ret);
- return ret;
- }
-
- hdmi_phy->pll_hw.init = &clk_init;
- hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
- if (IS_ERR(hdmi_phy->pll)) {
- ret = PTR_ERR(hdmi_phy->pll);
- dev_err(dev, "Failed to register PLL: %d\n", ret);
- return ret;
- }
-
- ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
- &hdmi_phy->ibias);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret);
- return ret;
- }
-
- ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
- &hdmi_phy->ibias_up);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret);
- return ret;
- }
-
- dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
- hdmi_phy->drv_imp_clk = 0x30;
- hdmi_phy->drv_imp_d2 = 0x30;
- hdmi_phy->drv_imp_d1 = 0x30;
- hdmi_phy->drv_imp_d0 = 0x30;
-
- phy = devm_phy_create(dev, NULL, &mtk_hdmi_phy_ops);
- if (IS_ERR(phy)) {
- dev_err(dev, "Failed to create HDMI PHY\n");
- return PTR_ERR(phy);
- }
- phy_set_drvdata(phy, hdmi_phy);
-
- phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
- hdmi_phy->dev = dev;
- return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
- hdmi_phy->pll);
-}
-
-static int mtk_hdmi_phy_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-static const struct of_device_id mtk_hdmi_phy_match[] = {
- { .compatible = "mediatek,mt8173-hdmi-phy", },
- {},
-};
-
-struct platform_driver mtk_hdmi_phy_driver = {
- .probe = mtk_hdmi_phy_probe,
- .remove = mtk_hdmi_phy_remove,
- .driver = {
- .name = "mediatek-hdmi-phy",
- .of_match_table = mtk_hdmi_phy_match,
- },
+struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf = {
+ .tz_enabled = true,
+ .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops,
+ .hdmi_phy_dev_ops = &mtk_hdmi_phy_dev_ops,
};
MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>");
--
2.12.5
^ permalink raw reply related
* [PATCH 5/7] drm/mediatek: implement connection from BLS to DPI0
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
Modify display driver to support connection from BLS to DPI.
Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index 8130f3dab661..289a68c6731f 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -35,6 +35,7 @@
#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030
#define DISP_REG_CONFIG_OUT_SEL 0x04c
#define DISP_REG_CONFIG_DSI_SEL 0x050
+#define DISP_REG_CONFIG_DPI_SEL 0x064
#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n))
#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
@@ -84,7 +85,10 @@
#define OVL_MOUT_EN_RDMA 0x1
#define BLS_TO_DSI_RDMA1_TO_DPI1 0x8
+#define BLS_TO_DPI_RDMA1_TO_DSI 0x2
#define DSI_SEL_IN_BLS 0x0
+#define DPI_SEL_IN_BLS 0x0
+#define DSI_SEL_IN_RDMA 0x1
struct mtk_disp_mutex {
int id;
@@ -189,9 +193,17 @@ static void mtk_ddp_sout_sel(void __iomem *config_regs,
enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next)
{
- if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0)
+ if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) {
writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1,
config_regs + DISP_REG_CONFIG_OUT_SEL);
+ } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DPI0) {
+ writel_relaxed(BLS_TO_DPI_RDMA1_TO_DSI,
+ config_regs + DISP_REG_CONFIG_OUT_SEL);
+ writel_relaxed(DSI_SEL_IN_RDMA,
+ config_regs + DISP_REG_CONFIG_DSI_SEL);
+ writel_relaxed(DPI_SEL_IN_BLS,
+ config_regs + DISP_REG_CONFIG_DPI_SEL);
+ }
}
void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
--
2.12.5
^ permalink raw reply related
* [PATCH 6/7] drm/mediatek: add a error return value when clock driver has been prepared
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
DRM driver get the comp->clk by of_clk_get(), we only
assign NULL to comp->clk when error happened, but do
not return the error number.
Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 4672317e3ad1..d38a5303f8fc 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -283,7 +283,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
comp->irq = of_irq_get(node, 0);
comp->clk = of_clk_get(node, 0);
if (IS_ERR(comp->clk))
- comp->clk = NULL;
+ return PTR_ERR(comp->clk);
/* Only DMA capable components need the LARB property */
comp->larb_dev = NULL;
--
2.12.5
^ permalink raw reply related
* [PATCH 7/7] drm/mediatek: config component output by device node port
From: Bibby Hsieh @ 2018-05-08 2:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508022057.29379-1-bibby.hsieh@mediatek.com>
We can select output component by decive node port.
Main path default output component is DSI.
External path default output component is DPI.
Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
---
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 37 ++++++++++++++++++++++++++++++----
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 4 ++--
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index f4fb86ab7b8d..05333769d862 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -24,6 +24,8 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp.h"
@@ -133,7 +135,7 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
.atomic_commit = mtk_atomic_commit,
};
-static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
+static enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
DDP_COMPONENT_OVL0,
DDP_COMPONENT_RDMA0,
DDP_COMPONENT_COLOR0,
@@ -141,12 +143,12 @@ static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
DDP_COMPONENT_DSI0,
};
-static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
+static enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
DDP_COMPONENT_RDMA1,
DDP_COMPONENT_DPI0,
};
-static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
+static enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
DDP_COMPONENT_OVL0,
DDP_COMPONENT_COLOR0,
DDP_COMPONENT_AAL,
@@ -157,7 +159,7 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
DDP_COMPONENT_PWM0,
};
-static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
+static enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
DDP_COMPONENT_OVL1,
DDP_COMPONENT_COLOR1,
DDP_COMPONENT_GAMMA,
@@ -411,6 +413,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
/* Iterate over sibling DISP function blocks */
for_each_child_of_node(dev->of_node->parent, node) {
+ struct device_node *port, *ep, *remote;
const struct of_device_id *of_id;
enum mtk_ddp_comp_type comp_type;
int comp_id;
@@ -470,6 +473,32 @@ static int mtk_drm_probe(struct platform_device *pdev)
private->ddp_comp[comp_id] = comp;
}
+
+ if (comp_type != MTK_DSI && comp_type != MTK_DPI) {
+ port = of_graph_get_port_by_id(node, 0);
+ if (!port)
+ continue;
+ ep = of_get_child_by_name(port, "endpoint");
+ of_node_put(port);
+ if (!ep)
+ continue;
+ remote = of_graph_get_remote_port_parent(ep);
+ of_node_put(ep);
+ if (!remote)
+ continue;
+ of_id = of_match_node(mtk_ddp_comp_dt_ids, remote);
+ if (!of_id)
+ continue;
+ comp_type = (enum mtk_ddp_comp_type)of_id->data;
+ for (i = 0; i < private->data->main_len - 1; i++)
+ if (private->data->main_path[i] == comp_id)
+ private->data->main_path[i + 1] =
+ mtk_ddp_comp_get_id(node, comp_type);
+ for (i = 0; i < private->data->ext_len - 1; i++)
+ if (private->data->ext_path[i] == comp_id)
+ private->data->ext_path[i + 1] =
+ mtk_ddp_comp_get_id(node, comp_type);
+ }
}
if (!private->mutex_node) {
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index c3378c452c0a..2bcba8eb06f4 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -29,9 +29,9 @@ struct drm_property;
struct regmap;
struct mtk_mmsys_driver_data {
- const enum mtk_ddp_comp_id *main_path;
+ enum mtk_ddp_comp_id *main_path;
unsigned int main_len;
- const enum mtk_ddp_comp_id *ext_path;
+ enum mtk_ddp_comp_id *ext_path;
unsigned int ext_len;
bool shadow_register;
};
--
2.12.5
^ permalink raw reply related
* [RESEND PATCH] pinctrl: rockchip: Disable interrupt when changing it's capability
From: JeffyChen @ 2018-05-08 2:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508015623.GA61455@rodete-desktop-imager.corp.google.com>
Hi Brian,
On 05/08/2018 09:56 AM, Brian Norris wrote:
> On Tue, May 08, 2018 at 09:36:24AM +0800, Jeffy Chen wrote:
>> On 05/08/2018 06:15 AM, Brian Norris wrote:
>>> On the other hand...this also implies there may be a race condition
>>> there, where we might lose an interrupt if there is an edge between the
>>> re-configuration of the polarity in rockchip_irq_demux() and the
>>> clearing/handling of the interrupt (handle_edge_irq() ->
>>> chip->irq_ack()). If we have an edge between there, then we might ack
>>> it, but leave the polarity such that we aren't ready for the next
>>> (inverted) edge.
>>
>> if let me guess, the unexpected irq we saw is the hardware trying to avoid
>> losing irq? for example, we set a EDGE_RISING, and the hardware saw the gpio
>> is already high, then though it might lost an irq, so fake one for safe?
>
> I won't pretend to know what the IC designers were doing, but I don't
> think that would resolve the problem I'm talking about. The sequence is
> something like:
> 1. EDGE_BOTH IRQ occurs (e.g., low to high)
> 2. reconfigure polarity in rockchip_irq_demux() (polarity=low)
> 3. continue to handle_edge_irq()
> 4. another HW edge occurs (e.g., high to low)
> 5. handle_edge_irq() (from 3) acks (clears) IRQ (before a subsequent
> rockchip_irq_demux() gets a chance to run and flip the polarity)
> ...
>
> Now the polarity is still low, but the next trigger should be a
> low-to-high edge.
oops, i see the problem.
so what if we do these:
1/ edge irq triggered
2/ read gpio level
3/ handle irq(ack irq)
4/ toggle edge mode(with a while gpio level check)
if the gpio changed in 2/ -> 3/, the 4/ will trigger an irq when writing
GPIO_INT_POLARITY(which is what we are trying to avoid in the set_type case)
but this would not work if i'm wrong about how the HW fake an irq when
changing POLARITY...
or maybe we could just check the gpio status again after
handle_edge_irq, and correct the polarity in this case
>
>> i'll try to confirm it with IC guys.
>
> Brian
>
>
>
^ permalink raw reply
* [PATCH v0 0/2] Add sdmmc UHS support to ROC-RK3328-CC board
From: djw at t-chip.com.cn @ 2018-05-08 2:48 UTC (permalink / raw)
To: linux-arm-kernel
From: Levin Du <djw@t-chip.com.cn>
Hi all,
This is an attemp to add sdmmc UHS support to the ROC-RK3328-CC board.
It adds a new compatible `rockchip,rk3328-gpio-syscon10` to the gpio-syscon
driver, so that a new gpio controller named `gpio_syscon10` can be defined
and used in the regulator-gpio. This regulator controls the signal voltage of the
sdmmc. It is essential for UHS support which requires 1.8V signal voltage.
Levin Du (2):
gpio: syscon: Add gpio-syscon for rk3328
arm64: dts: rockchip: Add sdmmc UHS support for roc-rk3328-cc
arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 36 ++++++++++++++++++++++++++
drivers/gpio/gpio-syscon.c | 32 +++++++++++++++++++++++
2 files changed, 68 insertions(+)
--
2.7.4
^ permalink raw reply
* [PATCH v0 2/2] arm64: dts: rockchip: Add sdmmc UHS support for roc-rk3328-cc
From: djw at t-chip.com.cn @ 2018-05-08 2:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525747704-8537-1-git-send-email-djw@t-chip.com.cn>
From: Levin Du <djw@t-chip.com.cn>
In roc-rk3328-cc board, the signal voltage of sdmmc is supplied by
the vcc_sdio regulator, which is a mux between 1.8V and 3.3V,
controlled by a special output only gpio pin.
However, this pin, not being a normal gpio in the rockchip pinctrl,
is set by bit 1 of system register GRF_SOC_CON10. Therefore a new
gpio controller using gpio-syscon driver is defined in order to use
regulator-gpio.
If the signal voltage changes, the io domain needs to change
correspondingly.
To use this feature, the following options are required in kernel config:
- CONFIG_GPIO_SYSCON=y
- CONFIG_POWER_AVS=y
- CONFIG_ROCKCHIP_IODOMAIN=y
Signed-off-by: Levin Du <djw@t-chip.com.cn>
---
arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 36 ++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
index 246c317..792cb04 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
@@ -14,6 +14,12 @@
stdout-path = "serial2:1500000n8";
};
+ gpio_syscon10: gpio-syscon10 {
+ compatible = "rockchip,rk3328-gpio-syscon10";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
gmac_clkin: external-gmac-clock {
compatible = "fixed-clock";
clock-frequency = <125000000>;
@@ -41,6 +47,19 @@
vin-supply = <&vcc_io>;
};
+ vcc_sdio: sdmmcio-regulator {
+ compatible = "regulator-gpio";
+ gpios = <&gpio_syscon10 1 GPIO_ACTIVE_HIGH>;
+ states = <1800000 0x1
+ 3300000 0x0>;
+ regulator-name = "vcc_sdio";
+ regulator-type = "voltage";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ vin-supply = <&vcc_sys>;
+ };
+
vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator {
compatible = "regulator-fixed";
enable-active-high;
@@ -208,6 +227,18 @@
};
};
+&io_domains {
+ status = "okay";
+
+ vccio1-supply = <&vcc_io>;
+ vccio2-supply = <&vcc18_emmc>;
+ vccio3-supply = <&vcc_sdio>;
+ vccio4-supply = <&vcc_18>;
+ vccio5-supply = <&vcc_io>;
+ vccio6-supply = <&vcc_io>;
+ pmuio-supply = <&vcc_io>;
+};
+
&pinctrl {
pmic {
pmic_int_l: pmic-int-l {
@@ -227,10 +258,15 @@
cap-mmc-highspeed;
cap-sd-highspeed;
disable-wp;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
max-frequency = <150000000>;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>;
vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vcc_sdio>;
status = "okay";
};
--
2.7.4
^ permalink raw reply related
* [RESEND PATCH] pinctrl: rockchip: Disable interrupt when changing it's capability
From: JeffyChen @ 2018-05-08 2:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5AF10C10.1070003@rock-chips.com>
Hi Brian,
On 05/08/2018 10:31 AM, JeffyChen wrote:
> Hi Brian,
>
> On 05/08/2018 09:56 AM, Brian Norris wrote:
>> On Tue, May 08, 2018 at 09:36:24AM +0800, Jeffy Chen wrote:
>>> On 05/08/2018 06:15 AM, Brian Norris wrote:
>>>> On the other hand...this also implies there may be a race condition
>>>> there, where we might lose an interrupt if there is an edge between the
>>>> re-configuration of the polarity in rockchip_irq_demux() and the
>>>> clearing/handling of the interrupt (handle_edge_irq() ->
>>>> chip->irq_ack()). If we have an edge between there, then we might ack
>>>> it, but leave the polarity such that we aren't ready for the next
>>>> (inverted) edge.
>>>
>>> if let me guess, the unexpected irq we saw is the hardware trying to
>>> avoid
>>> losing irq? for example, we set a EDGE_RISING, and the hardware saw
>>> the gpio
>>> is already high, then though it might lost an irq, so fake one for safe?
>>
>> I won't pretend to know what the IC designers were doing, but I don't
>> think that would resolve the problem I'm talking about. The sequence is
>> something like:
>> 1. EDGE_BOTH IRQ occurs (e.g., low to high)
>> 2. reconfigure polarity in rockchip_irq_demux() (polarity=low)
>> 3. continue to handle_edge_irq()
>> 4. another HW edge occurs (e.g., high to low)
>> 5. handle_edge_irq() (from 3) acks (clears) IRQ (before a subsequent
>> rockchip_irq_demux() gets a chance to run and flip the polarity)
>> ...
>>
>> Now the polarity is still low, but the next trigger should be a
>> low-to-high edge.
>
> oops, i see the problem.
>
> so what if we do these:
> 1/ edge irq triggered
> 2/ read gpio level
> 3/ handle irq(ack irq)
> 4/ toggle edge mode(with a while gpio level check)
>
> if the gpio changed in 2/ -> 3/, the 4/ will trigger an irq when writing
> GPIO_INT_POLARITY(which is what we are trying to avoid in the set_type
> case)
>
> but this would not work if i'm wrong about how the HW fake an irq when
> changing POLARITY...
>
>
> or maybe we could just check the gpio status again after
> handle_edge_irq, and correct the polarity in this case
i saw the pinctrl-msm.c do this in the ack(),
and also at the end of set_type(), which might avoid another race in the
set_type()
>
>>
>>> i'll try to confirm it with IC guys.
>>
>> Brian
>>
>>
>>
>
^ permalink raw reply
* [PATCH] ASoC: uniphier: add digital output volume for UniPhier sound system
From: Katsuhiro Suzuki @ 2018-05-08 3:16 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds controllers for digital volume of PCM output. Volume
effects simply linear, not dB scale as follows:
Gained PCM = Original * 0x4000 / Volume
The value range of volume is from 0x0001 to 0xffff. 0x0000 works as
mute. Initial value is 0x4000 (+0dB).
Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
sound/soc/uniphier/aio-core.c | 58 ++++++++++++++
sound/soc/uniphier/aio-cpu.c | 140 ++++++++++++++++++++++++++++++++++
sound/soc/uniphier/aio-reg.h | 33 ++++++--
sound/soc/uniphier/aio.h | 7 ++
4 files changed, 233 insertions(+), 5 deletions(-)
diff --git a/sound/soc/uniphier/aio-core.c b/sound/soc/uniphier/aio-core.c
index e37b80921abb..638cb3fc5f7b 100644
--- a/sound/soc/uniphier/aio-core.c
+++ b/sound/soc/uniphier/aio-core.c
@@ -659,6 +659,64 @@ void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
}
}
+/**
+ * aio_port_get_volume - get volume of AIO port block
+ * @sub: the AIO substream pointer
+ *
+ * Return: current volume, range is 0x0000 - 0xffff
+ */
+int aio_port_get_volume(struct uniphier_aio_sub *sub)
+{
+ struct regmap *r = sub->aio->chip->regmap;
+ u32 v;
+
+ regmap_read(r, OPORTMXTYVOLGAINSTATUS(sub->swm->oport.map, 0), &v);
+
+ return FIELD_GET(OPORTMXTYVOLGAINSTATUS_CUR_MASK, v);
+}
+
+/**
+ * aio_port_set_volume - set volume of AIO port block
+ * @sub: the AIO substream pointer
+ * @vol: target volume, range is 0x0000 - 0xffff.
+ *
+ * Change digital volume and perfome fade-out/fade-in effect for specified
+ * output slot of port. Gained PCM value can calculate as the following:
+ * Gained = Original * vol / 0x4000
+ */
+void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
+{
+ struct regmap *r = sub->aio->chip->regmap;
+ int oport_map = sub->swm->oport.map;
+ int cur, diff, slope = 0, fs;
+
+ if (sub->swm->dir == PORT_DIR_INPUT)
+ return;
+
+ cur = aio_port_get_volume(sub);
+ diff = abs(vol - cur);
+ fs = params_rate(&sub->params);
+ if (fs)
+ slope = diff / AUD_VOL_FADE_TIME * 1000 / fs;
+ slope = max(1, slope);
+
+ regmap_update_bits(r, OPORTMXTYVOLPARA1(oport_map, 0),
+ OPORTMXTYVOLPARA1_SLOPEU_MASK, slope << 16);
+ regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
+ OPORTMXTYVOLPARA2_TARGET_MASK, vol);
+
+ if (cur < vol)
+ regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
+ OPORTMXTYVOLPARA2_FADE_MASK,
+ OPORTMXTYVOLPARA2_FADE_FADEIN);
+ else
+ regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
+ OPORTMXTYVOLPARA2_FADE_MASK,
+ OPORTMXTYVOLPARA2_FADE_FADEOUT);
+
+ regmap_write(r, AOUTFADECTR0, BIT(oport_map));
+}
+
/**
* aio_if_set_param - set parameters of AIO DMA I/F block
* @sub: the AIO substream pointer
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
index 00b6441bf195..80daec17be25 100644
--- a/sound/soc/uniphier/aio-cpu.c
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -32,6 +32,35 @@ static bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
return chip->plls[pll_id].enable;
}
+/**
+ * find_volume - find volume supported HW port by HW port number
+ * @chip: the AIO chip pointer
+ * @oport_hw: HW port number, one of AUD_HW_XXXX
+ *
+ * Find AIO device from device list by HW port number. Volume feature is
+ * available only in Output and PCM ports, this limitation comes from HW
+ * specifications.
+ *
+ * Return: The pointer of AIO substream if successful, otherwise NULL on error.
+ */
+static struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip,
+ int oport_hw)
+{
+ int i;
+
+ for (i = 0; i < chip->num_aios; i++) {
+ struct uniphier_aio_sub *sub = &chip->aios[i].sub[0];
+
+ if (!sub->swm)
+ continue;
+
+ if (sub->swm->oport.hw == oport_hw)
+ return sub;
+ }
+
+ return NULL;
+}
+
static bool match_spec(const struct uniphier_aio_spec *spec,
const char *name, int dir)
{
@@ -287,6 +316,7 @@ static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
sub->setting = 1;
aio_port_reset(sub);
+ aio_port_set_volume(sub, sub->vol);
aio_src_reset(sub);
return 0;
@@ -373,6 +403,8 @@ int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
sub->swm = &spec->swm;
sub->spec = spec;
+
+ sub->vol = AUD_VOL_INIT;
}
aio_iecout_set_enable(aio->chip, true);
@@ -449,8 +481,116 @@ int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
}
EXPORT_SYMBOL_GPL(uniphier_aio_dai_resume);
+static int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = AUD_VOL_MAX;
+
+ return 0;
+}
+
+static int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
+ struct uniphier_aio_sub *sub;
+ int oport_hw = kcontrol->private_value;
+
+ sub = find_volume(chip, oport_hw);
+ if (!sub)
+ return 0;
+
+ ucontrol->value.integer.value[0] = sub->vol;
+
+ return 0;
+}
+
+static int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
+ struct uniphier_aio_sub *sub;
+ int oport_hw = kcontrol->private_value;
+
+ sub = find_volume(chip, oport_hw);
+ if (!sub)
+ return 0;
+
+ if (sub->vol == ucontrol->value.integer.value[0])
+ return 0;
+ sub->vol = ucontrol->value.integer.value[0];
+
+ aio_port_set_volume(sub, sub->vol);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new uniphier_aio_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "HPCMOUT1 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_HPCMOUT1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "PCMOUT1 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_PCMOUT1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "PCMOUT2 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_PCMOUT2,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "PCMOUT3 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_PCMOUT3,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "HIECOUT1 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_HIECOUT1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "IECOUT1 Volume",
+ .info = uniphier_aio_vol_info,
+ .get = uniphier_aio_vol_get,
+ .put = uniphier_aio_vol_put,
+ .private_value = AUD_HW_IECOUT1,
+ },
+};
+
static const struct snd_soc_component_driver uniphier_aio_component = {
.name = "uniphier-aio",
+ .controls = uniphier_aio_controls,
+ .num_controls = ARRAY_SIZE(uniphier_aio_controls),
};
int uniphier_aio_probe(struct platform_device *pdev)
diff --git a/sound/soc/uniphier/aio-reg.h b/sound/soc/uniphier/aio-reg.h
index 511ea3c01847..45fdc6ae358a 100644
--- a/sound/soc/uniphier/aio-reg.h
+++ b/sound/soc/uniphier/aio-reg.h
@@ -169,6 +169,7 @@
#define PBINMXPAUSECTR1(n) (0x20208 + 0x40 * (n))
/* AOUT */
+#define AOUTFADECTR0 0x40020
#define AOUTENCTR0 0x40040
#define AOUTENCTR1 0x40044
#define AOUTENCTR2 0x40048
@@ -179,6 +180,9 @@
#define AOUTSRCRSTCTR1 0x400c4
#define AOUTSRCRSTCTR2 0x400c8
+/* AOUT PCMOUT has 5 slots, slot0-3: D0-3, slot4: DMIX */
+#define OPORT_SLOT_MAX 5
+
/* AOUT(PCMOUTN) */
#define OPORTMXCTR1(n) (0x42000 + 0x400 * (n))
#define OPORTMXCTR1_I2SLRSEL_MASK (0x11 << 10)
@@ -359,11 +363,30 @@
#define OPORTMXMASK_XCKMSK_ON (0x0 << 0)
#define OPORTMXMASK_XCKMSK_OFF (0x7 << 0)
#define OPORTMXDEBUG(n) (0x420fc + 0x400 * (n))
-#define OPORTMXT0RSTCTR(n) (0x4211c + 0x400 * (n))
-#define OPORTMXT1RSTCTR(n) (0x4213c + 0x400 * (n))
-#define OPORTMXT2RSTCTR(n) (0x4215c + 0x400 * (n))
-#define OPORTMXT3RSTCTR(n) (0x4217c + 0x400 * (n))
-#define OPORTMXT4RSTCTR(n) (0x4219c + 0x400 * (n))
+#define OPORTMXTYVOLPARA1(n, m) (0x42100 + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXTYVOLPARA1_SLOPEU_MASK GENMASK(31, 16)
+#define OPORTMXTYVOLPARA2(n, m) (0x42104 + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXTYVOLPARA2_FADE_MASK GENMASK(17, 16)
+#define OPORTMXTYVOLPARA2_FADE_NOOP (0x0 << 16)
+#define OPORTMXTYVOLPARA2_FADE_FADEOUT (0x1 << 16)
+#define OPORTMXTYVOLPARA2_FADE_FADEIN (0x2 << 16)
+#define OPORTMXTYVOLPARA2_TARGET_MASK GENMASK(15, 0)
+#define OPORTMXTYVOLGAINSTATUS(n, m) (0x42108 + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXTYVOLGAINSTATUS_CUR_MASK GENMASK(15, 0)
+#define OPORTMXTYSLOTCTR(n, m) (0x42114 + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXTYSLOTCTR_SLOTSEL_MASK GENMASK(11, 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT0 (0x8 << 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT1 (0x9 << 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT2 (0xa << 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT3 (0xb << 8)
+#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT4 (0xc << 8)
+#define OPORTMXT0SLOTCTR_MUTEOFF_MASK BIT(1)
+#define OPORTMXT0SLOTCTR_MUTEOFF_MUTE (0x0 << 1)
+#define OPORTMXT0SLOTCTR_MUTEOFF_UNMUTE (0x1 << 1)
+#define OPORTMXTYRSTCTR(n, m) (0x4211c + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXT0RSTCTR_RST_MASK BIT(1)
+#define OPORTMXT0RSTCTR_RST_OFF (0x0 << 1)
+#define OPORTMXT0RSTCTR_RST_ON (0x1 << 1)
#define SBF_(frame, shift) (((frame) * 2 - 1) << shift)
diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h
index 52670126084f..aa89c2f6fa24 100644
--- a/sound/soc/uniphier/aio.h
+++ b/sound/soc/uniphier/aio.h
@@ -130,6 +130,10 @@ enum IEC61937_PC {
#define AUD_PLLDIV_1_1 2
#define AUD_PLLDIV_2_3 3
+#define AUD_VOL_INIT 0x4000 /* +0dB */
+#define AUD_VOL_MAX 0xffff /* +6dB */
+#define AUD_VOL_FADE_TIME 20 /* 20ms */
+
#define AUD_RING_SIZE (128 * 1024)
#define AUD_MIN_FRAGMENT 4
@@ -231,6 +235,7 @@ struct uniphier_aio_sub {
/* For PCM audio */
struct snd_pcm_substream *substream;
struct snd_pcm_hw_params params;
+ int vol;
/* For compress audio */
struct snd_compr_stream *cstream;
@@ -323,6 +328,8 @@ int aio_port_set_clk(struct uniphier_aio_sub *sub);
int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
const struct snd_pcm_hw_params *params);
void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable);
+int aio_port_get_volume(struct uniphier_aio_sub *sub);
+void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol);
int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through);
int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
enum IEC61937_PC pc);
--
2.17.0
^ permalink raw reply related
* [PATCH net-next v2 00/13] net: mvpp2: phylink conversion
From: David Miller @ 2018-05-08 3:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180504135643.23466-1-antoine.tenart@bootlin.com>
From: Antoine Tenart <antoine.tenart@bootlin.com>
Date: Fri, 4 May 2018 15:56:30 +0200
> Also as the SFP cages on both DB boards can be considered as non-wired,
> the SFP code was reworked to really support when some pins of the SFP
> cage aren't described in the device tree. Also a warning was added when
> no Tx disable pin is available. (Patches 1-3).
I guess there is still discussion about whether fixed-link should be
used for this instead of SFP.
^ 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