* [PATCH 1/3] clk: Hi6220: enable stub clock driver for ARCH_HISI
From: Stephen Boyd @ 2016-11-15 2:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161112120231.GB23848@leoy-linaro>
On 11/12, Leo Yan wrote:
> Hi Stephen,
>
> On Wed, Aug 31, 2016 at 03:40:49PM -0700, Stephen Boyd wrote:
> > On 08/31, Leo Yan wrote:
> > > In current kernel config 'CONFIG_STUB_CLK_HI6220' is disabled by
> > > default, as result stub clock driver has not been registered and
> > > CPUFreq driver cannot work.
> > >
> > > This patch is to enable stub clock driver in config for ARCH_HISI.
> > >
> > > Reported-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
> > > Signed-off-by: Leo Yan <leo.yan@linaro.org>
> > > ---
> >
> > Acked-by: Stephen Boyd <sboyd@codeaurora.org>
>
> We found this patch is missed mainline kernel. So could you help pick
> it? Or do you need me resend this patch?
>
Sure I can fish it out and apply it.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH 1/3] clk: Hi6220: enable stub clock driver for ARCH_HISI
From: Stephen Boyd @ 2016-11-15 2:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1472633417-9330-2-git-send-email-leo.yan@linaro.org>
On 08/31, Leo Yan wrote:
> In current kernel config 'CONFIG_STUB_CLK_HI6220' is disabled by
> default, as result stub clock driver has not been registered and
> CPUFreq driver cannot work.
>
> This patch is to enable stub clock driver in config for ARCH_HISI.
>
> Reported-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
> Signed-off-by: Leo Yan <leo.yan@linaro.org>
> ---
Applied to clk-next
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH 3/4] fpga mgr: zynq: Add support for encrypted bitstreams
From: atull @ 2016-11-15 2:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161107001326.7395-4-moritz.fischer@ettus.com>
On Mon, 7 Nov 2016, Moritz Fischer wrote:
Hi Moritz,
This looks good. Probably the socfpga changes could get
folded into this patch (was patch 4/4) unless you thought of
a reason not to (after that patch is changed to see if the
MSEL bits are set to enable decrypt).
There also could be a uncompress cap as well since cyclone 5
supports both compressed and encrypted images and has bits
in the MSEL for them (I mentioned separately in my comments
about patch 4/4).
For the Zynq, does the encrypt bit denote a requirement that
the part will only take an encrypted image or is it an
option that it supports? IIRC (and my brain is currently
pretty tired), if the MSEL for Cyclone5 is set for
encryption, the bitsream must be encrypted (same for
compress). That might change the meaning of this stuff a
bit but probably doesn't necessitate a change in the
implementation. It also makes the sysfs that much more
useful as it allows the users to know what type of image
they are required to provide.
Thanks,
Alan
> Add new flag FPGA_MGR_DECRYPT_BISTREAM as well as a matching
> capability FPGA_MGR_CAP_DECRYPT to allow for on-the-fly
> decryption of an encrypted bitstream.
>
> If the system is not booted in secure mode AES & HMAC units
> are disabled by the boot ROM, therefore the capability
> is not available.
>
> Signed-off-by: Moritz Fischer <moritz.fischer@ettus.com>
> Cc: Alan Tull <atull@opensource.altera.com>
> Cc: Michal Simek <michal.simek@xilinx.com>
> Cc: S?ren Brinkmann <soren.brinkmann@xilinx.com>
> Cc: linux-kernel at vger.kernel.org
> Cc: linux-arm-kernel at lists.infradead.org
> ---
> drivers/fpga/fpga-mgr.c | 7 +++++++
> drivers/fpga/zynq-fpga.c | 21 +++++++++++++++++++--
> include/linux/fpga/fpga-mgr.h | 2 ++
> 3 files changed, 28 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
> index 98230b7..e4d08e1 100644
> --- a/drivers/fpga/fpga-mgr.c
> +++ b/drivers/fpga/fpga-mgr.c
> @@ -61,6 +61,12 @@ int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, const char *buf,
> return -ENOTSUPP;
> }
>
> + if (flags & FPGA_MGR_DECRYPT_BITSTREAM &&
> + !fpga_mgr_has_cap(FPGA_MGR_CAP_DECRYPT, mgr->caps)) {
> + dev_err(dev, "Bitstream decryption not supported\n");
> + return -ENOTSUPP;
> + }
> +
> /*
> * Call the low level driver's write_init function. This will do the
> * device-specific things to get the FPGA into the state where it is
> @@ -170,6 +176,7 @@ static const char * const state_str[] = {
> static const char * const cap_str[] = {
> [FPGA_MGR_CAP_FULL_RECONF] = "Full reconfiguration",
> [FPGA_MGR_CAP_PARTIAL_RECONF] = "Partial reconfiguration",
> + [FPGA_MGR_CAP_DECRYPT] = "Decrypt bitstream on the fly",
> };
>
> static ssize_t name_show(struct device *dev,
> diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
> index 1d37ff0..0aa4705 100644
> --- a/drivers/fpga/zynq-fpga.c
> +++ b/drivers/fpga/zynq-fpga.c
> @@ -71,6 +71,10 @@
> #define CTRL_PCAP_PR_MASK BIT(27)
> /* Enable PCAP */
> #define CTRL_PCAP_MODE_MASK BIT(26)
> +/* Needed to reduce clock rate for secure config */
> +#define CTRL_PCAP_RATE_EN_MASK BIT(25)
> +/* System booted in secure mode */
> +#define CTRL_SEC_EN_MASK BIT(7)
>
> /* Miscellaneous Control Register bit definitions */
> /* Internal PCAP loopback */
> @@ -252,12 +256,20 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
>
> /* set configuration register with following options:
> * - enable PCAP interface
> - * - set throughput for maximum speed
> + * - set throughput for maximum speed (if we're not decrypting)
> * - set CPU in user mode
> */
> ctrl = zynq_fpga_read(priv, CTRL_OFFSET);
> - zynq_fpga_write(priv, CTRL_OFFSET,
> + if (flags & FPGA_MGR_DECRYPT_BITSTREAM) {
> + zynq_fpga_write(priv, CTRL_OFFSET,
> + (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK |
> + CTRL_PCAP_RATE_EN_MASK | ctrl));
> +
> + } else {
> + ctrl &= ~CTRL_PCAP_RATE_EN_MASK;
> + zynq_fpga_write(priv, CTRL_OFFSET,
> (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK | ctrl));
> + }
>
> /* check that we have room in the command queue */
> status = zynq_fpga_read(priv, STATUS_OFFSET);
> @@ -412,6 +424,7 @@ static int zynq_fpga_probe(struct platform_device *pdev)
> struct resource *res;
> fpga_mgr_cap_mask_t caps;
> int err;
> + u32 tmp;
>
> priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> if (!priv)
> @@ -466,6 +479,10 @@ static int zynq_fpga_probe(struct platform_device *pdev)
> fpga_mgr_cap_set(FPGA_MGR_CAP_FULL_RECONF, caps);
> fpga_mgr_cap_set(FPGA_MGR_CAP_PARTIAL_RECONF, caps);
>
> + /* only works if we booted in secure mode */
> + tmp = zynq_fpga_read(priv, CTRL_OFFSET);
> + if (tmp & CTRL_SEC_EN_MASK)
> + fpga_mgr_cap_set(FPGA_MGR_CAP_DECRYPT, caps);
>
> err = fpga_mgr_register(dev, "Xilinx Zynq FPGA Manager",
> &zynq_fpga_ops, caps, priv);
> diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h
> index 9bb96a5..aabe258 100644
> --- a/include/linux/fpga/fpga-mgr.h
> +++ b/include/linux/fpga/fpga-mgr.h
> @@ -68,10 +68,12 @@ enum fpga_mgr_states {
> */
> #define FPGA_MGR_PARTIAL_RECONFIG BIT(0)
> #define FPGA_MGR_FULL_RECONFIG BIT(1)
> +#define FPGA_MGR_DECRYPT_BITSTREAM BIT(2)
>
> enum fpga_mgr_capability {
> FPGA_MGR_CAP_PARTIAL_RECONF,
> FPGA_MGR_CAP_FULL_RECONF,
> + FPGA_MGR_CAP_DECRYPT,
>
> /* last capability type for creation of the capabilities mask */
> FPGA_MGR_CAP_END,
> --
> 2.10.0
>
>
^ permalink raw reply
* [PATCH 1/3] clk: Hi6220: enable stub clock driver for ARCH_HISI
From: Leo Yan @ 2016-11-15 2:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161115024100.GW5177@codeaurora.org>
On Mon, Nov 14, 2016 at 06:41:00PM -0800, Stephen Boyd wrote:
> On 08/31, Leo Yan wrote:
> > In current kernel config 'CONFIG_STUB_CLK_HI6220' is disabled by
> > default, as result stub clock driver has not been registered and
> > CPUFreq driver cannot work.
> >
> > This patch is to enable stub clock driver in config for ARCH_HISI.
> >
> > Reported-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
> > Signed-off-by: Leo Yan <leo.yan@linaro.org>
> > ---
>
> Applied to clk-next
Thanks :)
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
^ permalink raw reply
* [GIT PULL] i.MX fixes for 4.9, 2nd round
From: Shawn Guo @ 2016-11-15 2:43 UTC (permalink / raw)
To: linux-arm-kernel
The following changes since commit 4edd601c5a9c5094daa714e65063e623826f3bcc:
ARM: imx: mach-imx6q: Fix the PHY ID mask for AR8031 (2016-10-24 21:26:01 +0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git tags/imx-fixes-4.9-2
for you to fetch changes up to e3c9d9d6ebfeeeee29c6240e1b5978d40d31d21f:
ARM: dts: imx53-qsb: Fix regulator constraints (2016-11-05 16:18:16 +0800)
----------------------------------------------------------------
i.MX fixes for 4.9, 2nd round:
It fixes a boot failure on imx53-qsb board with a DA9053 PMIC, which is
caused by the regulator core change, commit fa93fd4ecc9c ("regulator:
core: Ensure we are at least in bounds for our constraints").
----------------------------------------------------------------
Fabio Estevam (1):
ARM: dts: imx53-qsb: Fix regulator constraints
arch/arm/boot/dts/imx53-qsb.dts | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
^ permalink raw reply
* [PATCH v2 2/3] irqchip: mtk-cirq: Add mediatek mtk-cirq implement
From: Youlin Pei @ 2016-11-15 2:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1f8f7b9f-7788-18c4-19c5-3c9a7623c188@arm.com>
On Thu, 2016-11-10 at 18:24 +0000, Marc Zyngier wrote:
> On 08/11/16 02:57, Youlin Pei wrote:
> > On Fri, 2016-11-04 at 22:21 +0000, Marc Zyngier wrote:
> >> On Fri, Nov 04 2016 at 04:42:57 AM, Youlin Pei <youlin.pei@mediatek.com> wrote:
> >>> On Tue, 2016-11-01 at 20:49 +0000, Marc Zyngier wrote:
> >>>> On Tue, Nov 01 2016 at 11:52:01 AM, Youlin Pei <youlin.pei@mediatek.com> wrote:
> >>>>> In Mediatek SOCs, the CIRQ is a low power interrupt controller
> >>>>> designed to works outside MCUSYS which comprises with Cortex-Ax
> >>>>> cores,CCI and GIC.
> >>>>>
> >>>>> The CIRQ controller is integrated in between MCUSYS( include
> >>>>> Cortex-Ax, CCI and GIC ) and interrupt sources as the second
> >>>>> level interrupt controller. The external interrupts which outside
> >>>>> MCUSYS will feed through CIRQ then bypass to GIC. CIRQ can monitors
> >>>>> all edge trigger interupts. When an edge interrupt is triggered,
> >>>>> CIRQ can record the status and generate a pulse signal to GIC when
> >>>>> flush command executed.
> >>>>>
> >>>>> When system enters sleep mode, MCUSYS will be turned off to improve
> >>>>> power consumption, also GIC is power down. The edge trigger interrupts
> >>>>> will be lost in this scenario without CIRQ.
> >>>>>
> >>>>> This commit provides the CIRQ irqchip implement.
> >>>>>
> >>>>> Signed-off-by: Youlin Pei <youlin.pei@mediatek.com>
> >>>>> ---
> >>>>> drivers/irqchip/Makefile | 2 +-
> >>>>> drivers/irqchip/irq-mtk-cirq.c | 262 ++++++++++++++++++++++++++++++++++++++++
> >>>>> 2 files changed, 263 insertions(+), 1 deletion(-)
> >>>>> create mode 100644 drivers/irqchip/irq-mtk-cirq.c
> >>>>>
> >>>>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> >>>>> index e4dbfc8..8f33580 100644
> >>>>> --- a/drivers/irqchip/Makefile
> >>>>> +++ b/drivers/irqchip/Makefile
> >>>>> @@ -60,7 +60,7 @@ obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o
> >>>>> obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
> >>>>> obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o
> >>>>> obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o
> >>>>> -obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o
> >>>>> +obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o irq-mtk-cirq.o
> >>>>> obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o
> >>>>> obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o
> >>>>> obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o
> >>>>> diff --git a/drivers/irqchip/irq-mtk-cirq.c b/drivers/irqchip/irq-mtk-cirq.c
> >>>>> new file mode 100644
> >>>>> index 0000000..fc43ef3
> >>>>> --- /dev/null
> >>>>> +++ b/drivers/irqchip/irq-mtk-cirq.c
> >>>>> @@ -0,0 +1,262 @@
> >>>>> +/*
> >>>>> + * Copyright (c) 2016 MediaTek Inc.
> >>>>> + * Author: Youlin.Pei <youlin.pei@mediatek.com>
> >>>>> + *
> >>>>> + * This program is free software; you can redistribute it and/or modify
> >>>>> + * it under the terms of the GNU General Public License version 2 as
> >>>>> + * published by the Free Software Foundation.
> >>>>> + *
> >>>>> + * This program is distributed in the hope that it will be useful,
> >>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> >>>>> + * GNU General Public License for more details.
> >>>>> + */
> >>>>> +
> >>>>> +#include <linux/irq.h>
> >>>>> +#include <linux/irqchip.h>
> >>>>> +#include <linux/irqdomain.h>
> >>>>> +#include <linux/of.h>
> >>>>> +#include <linux/of_irq.h>
> >>>>> +#include <linux/of_address.h>
> >>>>> +#include <linux/io.h>
> >>>>> +#include <linux/slab.h>
> >>>>> +#include <linux/syscore_ops.h>
> >>>>> +
> >>>>> +#define CIRQ_ACK 0x40
> >>>>> +#define CIRQ_MASK_SET 0xc0
> >>>>> +#define CIRQ_MASK_CLR 0x100
> >>>>> +#define CIRQ_SENS_SET 0x180
> >>>>> +#define CIRQ_SENS_CLR 0x1c0
> >>>>> +#define CIRQ_POL_SET 0x240
> >>>>> +#define CIRQ_POL_CLR 0x280
> >>>>> +#define CIRQ_CONTROL 0x300
> >>>>> +
> >>>>> +#define CIRQ_EN 0x1
> >>>>> +#define CIRQ_EDGE 0x2
> >>>>> +#define CIRQ_FLUSH 0x4
> >>>>> +
> >>>>> +#define CIRQ_IRQ_NUM 0x200
> >>>>> +
> >>>>> +struct mtk_cirq_chip_data {
> >>>>> + void __iomem *base;
> >>>>> + unsigned int ext_irq_start;
> >>>>> +};
> >>>>> +
> >>>>> +static struct mtk_cirq_chip_data *cirq_data;
> >>>>
> >>>> Are you guaranteed that you'll only ever have a single CIRQ in any
> >>>> system?
> >>>
> >>> In Mediatek's SOC, only hace a single CIRQ.
> >>>
> >>>>
> >>>>> +
> >>>>> +static void mtk_cirq_write_mask(struct irq_data *data, unsigned int offset)
> >>>>> +{
> >>>>> + struct mtk_cirq_chip_data *chip_data = data->chip_data;
> >>>>> + unsigned int cirq_num = data->hwirq;
> >>>>> + u32 mask = 1 << (cirq_num % 32);
> >>>>> +
> >>>>> + writel(mask, chip_data->base + offset + (cirq_num / 32) * 4);
> >>>>
> >>>> Why can't you use the relaxed accessors?
> >>>
> >>> It seems that i use wrong function, i will change the writel to
> >>> writel_relaxed in next ve
> >>>
> >>>>
> >>>>> +}
> >>>>> +
> >>>>> +static void mtk_cirq_mask(struct irq_data *data)
> >>>>> +{
> >>>>> + mtk_cirq_write_mask(data, CIRQ_MASK_SET);
> >>>>> + irq_chip_mask_parent(data);
> >>>>> +}
> >>>>> +
> >>>>> +static void mtk_cirq_unmask(struct irq_data *data)
> >>>>> +{
> >>>>> + mtk_cirq_write_mask(data, CIRQ_MASK_CLR);
> >>>>> + irq_chip_unmask_parent(data);
> >>>>> +}
> >>>>> +
> >>>>> +static void mtk_cirq_eoi(struct irq_data *data)
> >>>>> +{
> >>>>> + mtk_cirq_write_mask(data, CIRQ_ACK);
> >>>>
> >>>> EOI and ACK have very different semantics. What is this write actually
> >>>> doing? Also, you're now doing an additional MMIO write on each interrupt
> >>>> EOI, doubling its cost. Do you really need to do actually signal the HW
> >>>> that we've EOIed an interrupt? I would have hoped that you'd be able to
> >>>> put it in "bypass" mode as long as you're not suspending...
> >>>>
> >>>
> >>> When external interrupt happened, CIRQ status register record the status
> >>> even CIRQ is not enabled. when execute the flush command, CIRQ will
> >>> resend the signals according to the status. So if don't clear the
> >>> status, CIRQ will resend the wrong signals. the ACK write operation will
> >>> clear the status.
> >>
> >> But at this time, we haven't suspended yet, and there is nothing to
> >> replay. Also, you only enable the edge capture when suspending. So what
> >> are you ACKing here? Can't you simply clear everything right when
> >> suspending and not do it at all on the fast path?
> >
> > I had planned to ACK the status in cirq suspend callback, but
> > encountered a problem.
> > following is a piece of code from
> > http://lxr.free-electrons.com/source/kernel/power/suspend.c#L361
> >
> > arch_suspend_disable_irqs(); ---step1
> > BUG_ON(!irqs_disabled());
> >
> > error = syscore_suspend();
> > |
> > ---cirq suspend(); ---step2
> >
> > if ack the status in cirq suspend, the interrupts will be lost which
> > happened during step1 to step2.
> >
> > So would you mind give me some suggestions about this?
> > Thanks a lot!
>
> Right. So maybe there is a way:
> - On suspend you can iterate over all the cirq interrupts that have been
> recorded
> - For each of those, you inspect if it is pending at the GIC level
> (using the irq_get_irqchip_state helper)
> - if not pending, you Ack it, because it cannot be delivered anymore
> - If it is pending, then you know it happened between step 1 and step 2.
> - You then have the choice of either going into suspend and waking up
> immediately, or failing the suspend.
>
> Thoughts?
Will use this solution in next version.
Thanks a lot!
>
> M.
^ permalink raw reply
* [GIT PULL] i.MX clock updates for 4.10
From: Shawn Guo @ 2016-11-15 2:57 UTC (permalink / raw)
To: linux-arm-kernel
The following changes since commit 1001354ca34179f3db924eb66672442a173147dc:
Linux 4.9-rc1 (2016-10-15 12:17:50 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git tags/imx-clk-4.10
for you to fetch changes up to 73cd5e53caba2425f5b73ad0950544d1168ad27b:
clk: imx: clk-imx6ul: add clk support for imx6ull (2016-11-15 08:55:36 +0800)
----------------------------------------------------------------
i.MX clock updates for 4.10:
- A patch series to fix the long standing issue with glitchy parent
mux of ldb_di_clk, which can hang up LVDS display when ipu_di_clk
is sourced from ldb_di_clk.
- A patch to add imx6ull clock support on top of imx6ul clock driver.
----------------------------------------------------------------
Bai Ping (1):
clk: imx: clk-imx6ul: add clk support for imx6ull
Fabio Estevam (1):
clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK
Philipp Zabel (2):
clk: imx6: Mask mmdc_ch1 handshake for periph2_sel and mmdc_ch1_axi_podf
clk: imx6: Make the LDB_DI0 and LDB_DI1 clocks read-only
drivers/clk/imx/clk-imx6q.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
drivers/clk/imx/clk-imx6ul.c | 72 ++++++++++++++++++++++++++++++++++-------
drivers/clk/imx/clk.h | 8 +++++
include/dt-bindings/clock/imx6ul-clock.h | 15 ++++++++-
4 files changed, 356 insertions(+), 22 deletions(-)
^ permalink raw reply
* [linux-sunxi] Re: [PATCH v3 1/2] drm/bridge: dumb-vga-dac: Support a VDD regulator supply
From: Chen-Yu Tsai @ 2016-11-15 2:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v64tTacSAG1vvO28h8MN9JC9w+OzSrP+j2eTzqAiQKgaSA@mail.gmail.com>
Hi,
On Wed, Nov 2, 2016 at 9:33 AM, Chen-Yu Tsai <wens@csie.org> wrote:
> On Mon, Oct 31, 2016 at 2:28 PM, Rob Herring <robh@kernel.org> wrote:
>> On Sat, Oct 29, 2016 at 07:06:10PM +0800, Chen-Yu Tsai wrote:
>>> Some dumb VGA DACs are active components which require external power.
>>> Add support for specifying a regulator as its power supply.
>>>
>>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>>> ---
>>> .../bindings/display/bridge/dumb-vga-dac.txt | 2 ++
>>
>> For the binding,
>>
>> Acked-by: Rob Herring <robh@kernel.org>
Any comments on this patch from the DRM people?
ChenYu
>>
>> One code comment below...
>>
>>> drivers/gpu/drm/bridge/dumb-vga-dac.c | 35 ++++++++++++++++++++++
>>> 2 files changed, 37 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt b/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt
>>> index 003bc246a270..164cbb15f04c 100644
>>> --- a/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt
>>> +++ b/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt
>>> @@ -16,6 +16,8 @@ graph bindings specified in Documentation/devicetree/bindings/graph.txt.
>>> - Video port 0 for RGB input
>>> - Video port 1 for VGA output
>>>
>>> +Optional properties:
>>> +- vdd-supply: Power supply for DAC
>>>
>>> Example
>>> -------
>>> diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
>>> index afec232185a7..59781e031220 100644
>>> --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
>>> +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
>>> @@ -12,6 +12,7 @@
>>>
>>> #include <linux/module.h>
>>> #include <linux/of_graph.h>
>>> +#include <linux/regulator/consumer.h>
>>>
>>> #include <drm/drmP.h>
>>> #include <drm/drm_atomic_helper.h>
>>> @@ -23,6 +24,7 @@ struct dumb_vga {
>>> struct drm_connector connector;
>>>
>>> struct i2c_adapter *ddc;
>>> + struct regulator *vdd;
>>> };
>>>
>>> static inline struct dumb_vga *
>>> @@ -124,8 +126,33 @@ static int dumb_vga_attach(struct drm_bridge *bridge)
>>> return 0;
>>> }
>>>
>>> +static void dumb_vga_enable(struct drm_bridge *bridge)
>>> +{
>>> + struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge);
>>> + int ret;
>>> +
>>> + if (!IS_ERR(vga->vdd)) {
>>
>> if (IS_ERR())
>> return;
>>
>> ...will save some intentation.
>
> I thought about that, though if someone were to add more stuff to
> this, such as an enable GPIO, they might have to rework it. A standalone
> block of code would be easier to work with. I'm OK either way though.
>
> ChenYu
>
>>
>>> + ret = regulator_enable(vga->vdd);
>>> +
>>> + if (ret) {
>>> + DRM_ERROR("Failed to enable vdd regulator: %d\n", ret);
>>> + return;
>>> + }
>>> + }
>>> +}
>>> +
>>> +static void dumb_vga_disable(struct drm_bridge *bridge)
>>> +{
>>> + struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge);
>>> +
>>> + if (!IS_ERR(vga->vdd))
>>> + regulator_disable(vga->vdd);
>>> +}
>>> +
>>> static const struct drm_bridge_funcs dumb_vga_bridge_funcs = {
>>> .attach = dumb_vga_attach,
>>> + .enable = dumb_vga_enable,
>>> + .disable = dumb_vga_disable,
>>> };
>>>
>>> static struct i2c_adapter *dumb_vga_retrieve_ddc(struct device *dev)
>>> @@ -169,6 +196,14 @@ static int dumb_vga_probe(struct platform_device *pdev)
>>> return -ENOMEM;
>>> platform_set_drvdata(pdev, vga);
>>>
>>> + vga->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
>>> + if (IS_ERR(vga->vdd)) {
>>> + ret = PTR_ERR(vga->vdd);
>>> + if (ret == -EPROBE_DEFER)
>>> + return -EPROBE_DEFER;
>>> + dev_dbg(&pdev->dev, "No vdd regulator found: %d\n", ret);
>>> + }
>>> +
>>> vga->ddc = dumb_vga_retrieve_ddc(&pdev->dev);
>>> if (IS_ERR(vga->ddc)) {
>>> if (PTR_ERR(vga->ddc) == -ENODEV) {
>>> --
>>> 2.9.3
>>>
>>
>> --
>> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
>> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe at googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* [PATCH v2 1/3] binding: irqchip: mtk-cirq: Add binding document
From: Youlin Pei @ 2016-11-15 3:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161109182613.7tvzewua6ewxdvjc@rob-hp-laptop>
On Wed, 2016-11-09 at 12:26 -0600, Rob Herring wrote:
> On Tue, Nov 01, 2016 at 07:52:00PM +0800, Youlin Pei wrote:
> > This commit adds the device tree binding document for
> > the mediatek cirq.
> >
> > Signed-off-by: Youlin Pei <youlin.pei@mediatek.com>
> > ---
> > .../interrupt-controller/mediatek,cirq.txt | 30 ++++++++++++++++++++
> > 1 file changed, 30 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt
> >
> > diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt b/Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt
> > new file mode 100644
> > index 0000000..84e8123
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt
> > @@ -0,0 +1,30 @@
> > +* Mediatek 27xx cirq
> > +
> > +In Mediatek SOCs, the CIRQ is a low power interrupt controller designed to
> > +works outside MCUSYS which comprises with Cortex-Ax cores,CCI and GIC.
>
> s/works/work/
will fix in next version.
>
> > +The external interrupts (outside MCUSYS) will feed through CIRQ and connect
> > +to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive
> > +interrupts and generated a pulse signal to parent interrupt controller when
>
> s/generated/generate/
will fix in next version.
>
> > +flush command is executed. With CIRQ, MCUSYS can be completely turned off
> > +to improve the system power consumption without losing interrupts.
> > +
> > +Required properties:
> > +- compatible: should be: "mediatek,mtk-cirq".
>
> This should be SoC specific. This is fine as a fallback if the same
> block is in many SoCs, but mediatek and mtk is a bit redundant.
>
In next version, i will improve as following:
- compatible: Should be one of
- "mediatek,mt2701-cirq" for mt2701 CIRQ
- "mediatek,mt8173-cirq" for mt8173 CIRQ
- "mediatek,mt8135-cirq" for mt8135 CIRQ
and "mediatek,cirq" as a fallback.
> > +- interrupt-controller : Identifies the node as an interrupt controller.
> > +- #interrupt-cells : Use the same format as specified by GIC in arm,gic.txt.
> > +- interrupt-parent: phandle of irq parent for cirq. The parent must
> > + use the same interrupt-cells format as GIC.
> > +- reg: Physical base address of the cirq registers and length of memory
> > + mapped region.
> > +- mediatek,ext-irq-start: Identifies external irq start number in different
> > + SOCs.
>
> Wouldn't this always be 32 if the GIC is the parent? If 32 is the common
> case, then use the SoC compatible to determine this value.
>
ext-irq-start is not always 32. In different Socs, this value is
different.
Thanks a lot!
> > +
> > +Example:
> > + cirq: interrupt-controller at 10204000 {
> > + compatible = "mediatek,mtk-cirq";
> > + interrupt-controller;
> > + #interrupt-cells = <3>;
> > + interrupt-parent = <&sysirq>;
> > + reg = <0 0x10204000 0 0x4000>;
> > + mediatek,ext-irq-start = <32>;
> > + };
> > --
> > 1.7.9.5
> >
^ permalink raw reply
* [PATCH v2 1/2] phy: rockchip-inno-usb2: correct clk_ops callback
From: wlf @ 2016-11-15 3:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAD=FV=W36tdw3LqPq3tp58U4trYX6n=qaotMTsP6tm0QzZrRWQ@mail.gmail.com>
Hi Doug,
? 2016?11?15? 02:15, Doug Anderson ??:
> William
>
> On Sun, Nov 13, 2016 at 11:01 PM, William Wu <wulf@rock-chips.com> wrote:
>> Since we needs to delay ~1ms to wait for 480MHz output clock
>> of USB2 PHY to become stable after turn on it, the delay time
>> is pretty long for something that's supposed to be "atomic"
>> like a clk_enable(). Consider that clk_enable() will disable
>> interrupt and that a 1ms interrupt latency is not sensible.
>>
>> The 480MHz output clock should be handled in prepare callbacks
>> which support gate a clk if the operation may sleep.
>>
>> Signed-off-by: William Wu <wulf@rock-chips.com>
>> ---
>> drivers/phy/phy-rockchip-inno-usb2.c | 12 ++++++------
>> 1 file changed, 6 insertions(+), 6 deletions(-)
> Reviewed-by: Douglas Anderson <dianders@chromium.org>
Thanks! I'll add Reviewed-by.
>
>
>
^ permalink raw reply
* [PATCH v3 2/2] phy: rockchip-inno-usb2: correct 480MHz output clock stable time
From: wlf @ 2016-11-15 3:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAD=FV=VJsuiXV3NS0uroF2OWJEDn5eiCpX-jP3BOYgLZ8gy6Hw@mail.gmail.com>
Hi Doug,
? 2016?11?15? 02:17, Doug Anderson ??:
> William,
>
> On Mon, Nov 14, 2016 at 1:27 AM, William Wu <wulf@rock-chips.com> wrote:
>> We found that the system crashed due to 480MHz output clock of
>> USB2 PHY was unstable after clock had been enabled by gpu module.
>>
>> Theoretically, 1 millisecond is a critical value for 480MHz
>> output clock stable time, so we try to change the delay time
>> to 1.2 millisecond to avoid this issue.
>>
>> And the commit ed907fb1d7c3 ("phy: rockchip-inno-usb2: correct
>> clk_ops callback") used prepare callbacks instead of enable
>> callbacks to support gate a clk if the operation may sleep. So
>> we can switch from delay to sleep functions.
>>
>> Signed-off-by: William Wu <wulf@rock-chips.com>
>> ---
>> Changes in v3:
>> - fix kbuild test error: too few arguments to function 'usleep_range'
>>
>> Changes in v2:
>> - use usleep_range() function instead of mdelay()
>>
>> drivers/phy/phy-rockchip-inno-usb2.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
>> index 365e077..0e52b25 100644
>> --- a/drivers/phy/phy-rockchip-inno-usb2.c
>> +++ b/drivers/phy/phy-rockchip-inno-usb2.c
>> @@ -166,7 +166,7 @@ static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)
>> return ret;
>>
>> /* waitting for the clk become stable */
>> - mdelay(1);
>> + usleep_range(1200, 1300);
> Sight nit that you could also fix the spelling from "waitting" to "waiting".
>
> ...but that's pre-existing, so:
>
> Reviewed-by: Douglas Anderson <dianders@chromium.org>
Thanks! I'll add Reviewed-by and fix the spelling issue.
>
>
>
^ permalink raw reply
* [PATCH] arm64: dts: ls1046a: add qdma device tree node
From: hongbo.zhang at nxp.com @ 2016-11-15 3:24 UTC (permalink / raw)
To: linux-arm-kernel
From: Hongbo Zhang <hongbo.zhang@nxp.com>
The drivers/dma/fsl-qdma.c works for ls1046a too, this patch adds
device tree node for it.
Signed-off-by: Hongbo Zhang <hongbo.zhang@nxp.com>
---
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index 38806ca..6edf7cf 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -511,5 +511,19 @@
interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clockgen 4 1>;
};
+
+ qdma: qdma at 8380000 {
+ compatible = "fsl,ls1046a-qdma", "fsl,ls1021a-qdma";
+ reg = <0x0 0x838f000 0x0 0x11000 /* Controller regs */
+ 0x0 0x83a0000 0x0 0x40000>; /* Block regs */
+ interrupts = <0 152 0x4>,
+ <0 39 0x4>;
+ interrupt-names = "qdma-error", "qdma-queue";
+ channels = <8>;
+ queues = <2>;
+ status-sizes = <64>;
+ queue-sizes = <64 64>;
+ big-endian;
+ };
};
};
--
2.1.4
^ permalink raw reply related
* [PATCH 3/4] fpga mgr: zynq: Add support for encrypted bitstreams
From: Moritz Fischer @ 2016-11-15 3:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.10.1611142022380.6582@atull-VirtualBox>
Hi Alan,
On Mon, Nov 14, 2016 at 7:42 PM, atull <atull@opensource.altera.com> wrote:
> On Mon, 7 Nov 2016, Moritz Fischer wrote:
>
> Hi Moritz,
>
> This looks good. Probably the socfpga changes could get
> folded into this patch (was patch 4/4) unless you thought of
> a reason not to (after that patch is changed to see if the
> MSEL bits are set to enable decrypt).
Yeah. Agreed. I had kept that one separate because i was less
sure on how the socfpga stuff works. Will merge it together for
next revision.
>
> There also could be a uncompress cap as well since cyclone 5
> supports both compressed and encrypted images and has bits
> in the MSEL for them (I mentioned separately in my comments
> about patch 4/4).
Ok.
>
> For the Zynq, does the encrypt bit denote a requirement that
> the part will only take an encrypted image or is it an
> option that it supports? IIRC (and my brain is currently
> pretty tired), if the MSEL for Cyclone5 is set for
> encryption, the bitsream must be encrypted (same for
> compress). That might change the meaning of this stuff a
> bit but probably doesn't necessitate a change in the
> implementation. It also makes the sysfs that much more
> useful as it allows the users to know what type of image
> they are required to provide.
I don't think that's the case for Zynq. I think the actual reason for
different behavior is the fact that the AES unit now takes the
bitstream bytewise vs 4 bytes at a time, which is why the clock
needs to be divided by four. The TRM isn't overly specific on that.
I Will take another look in the Zynq 7000 TRM.
I do agree that the sysfs interface becomes more useful if
having an encrypted bitstream or compressed bitstream is now
mandatory. I'll need to think about this some more. Maybe to
make this useful there needs to be a distinction between
mandatory and optional capabilities. One could model it by
adding a PLAIN vs CRYPTED capability ... mhhh
Thanks for the review,
Moritz
^ permalink raw reply
* [PATCH v4 0/2] phy: rockchip-inno-usb2: correct 480MHz clk_ops callbacks and stable time
From: William Wu @ 2016-11-15 3:54 UTC (permalink / raw)
To: linux-arm-kernel
This series try to correct the 480MHz output clock of USB2 PHY
clk_ops callback and fix the delay time. It aims to make the
480MHz clock gate more sensible and stable.
Tested on rk3366/rk3399 EVB board.
William Wu (2):
phy: rockchip-inno-usb2: correct clk_ops callback
phy: rockchip-inno-usb2: correct 480MHz output clock stable time
drivers/phy/phy-rockchip-inno-usb2.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
--
2.0.0
^ permalink raw reply
* [PATCH v4 1/2] phy: rockchip-inno-usb2: correct clk_ops callback
From: William Wu @ 2016-11-15 3:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479182047-3399-1-git-send-email-wulf@rock-chips.com>
Since we needs to delay ~1ms to wait for 480MHz output clock
of USB2 PHY to become stable after turn on it, the delay time
is pretty long for something that's supposed to be "atomic"
like a clk_enable(). Consider that clk_enable() will disable
interrupt and that a 1ms interrupt latency is not sensible.
The 480MHz output clock should be handled in prepare callbacks
which support gate a clk if the operation may sleep.
Signed-off-by: William Wu <wulf@rock-chips.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
---
Changes in v4:
- add Reviewed-by
Changes in v3:
- None
Changes in v2:
- None
drivers/phy/phy-rockchip-inno-usb2.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
index ac20310..365e077 100644
--- a/drivers/phy/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/phy-rockchip-inno-usb2.c
@@ -153,7 +153,7 @@ static inline bool property_enabled(struct rockchip_usb2phy *rphy,
return tmp == reg->enable;
}
-static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw)
+static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)
{
struct rockchip_usb2phy *rphy =
container_of(hw, struct rockchip_usb2phy, clk480m_hw);
@@ -172,7 +172,7 @@ static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw)
return 0;
}
-static void rockchip_usb2phy_clk480m_disable(struct clk_hw *hw)
+static void rockchip_usb2phy_clk480m_unprepare(struct clk_hw *hw)
{
struct rockchip_usb2phy *rphy =
container_of(hw, struct rockchip_usb2phy, clk480m_hw);
@@ -181,7 +181,7 @@ static void rockchip_usb2phy_clk480m_disable(struct clk_hw *hw)
property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false);
}
-static int rockchip_usb2phy_clk480m_enabled(struct clk_hw *hw)
+static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw)
{
struct rockchip_usb2phy *rphy =
container_of(hw, struct rockchip_usb2phy, clk480m_hw);
@@ -197,9 +197,9 @@ rockchip_usb2phy_clk480m_recalc_rate(struct clk_hw *hw,
}
static const struct clk_ops rockchip_usb2phy_clkout_ops = {
- .enable = rockchip_usb2phy_clk480m_enable,
- .disable = rockchip_usb2phy_clk480m_disable,
- .is_enabled = rockchip_usb2phy_clk480m_enabled,
+ .prepare = rockchip_usb2phy_clk480m_prepare,
+ .unprepare = rockchip_usb2phy_clk480m_unprepare,
+ .is_prepared = rockchip_usb2phy_clk480m_prepared,
.recalc_rate = rockchip_usb2phy_clk480m_recalc_rate,
};
--
2.0.0
^ permalink raw reply related
* [PATCH v4 2/2] phy: rockchip-inno-usb2: correct 480MHz output clock stable time
From: William Wu @ 2016-11-15 3:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479182047-3399-1-git-send-email-wulf@rock-chips.com>
We found that the system crashed due to 480MHz output clock of
USB2 PHY was unstable after clock had been enabled by gpu module.
Theoretically, 1 millisecond is a critical value for 480MHz
output clock stable time, so we try to change the delay time
to 1.2 millisecond to avoid this issue.
And the commit ed907fb1d7c3 ("phy: rockchip-inno-usb2: correct
clk_ops callback") used prepare callbacks instead of enable
callbacks to support gate a clk if the operation may sleep. So
we can switch from delay to sleep functions.
Also fix a spelling error from "waitting" to "waiting".
Signed-off-by: William Wu <wulf@rock-chips.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
---
Changes in v4:
- add Reviewed-by and fix a spelling error
Changes in v3:
- None
Changes in v2:
- None
drivers/phy/phy-rockchip-inno-usb2.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
index 365e077..5d922fc 100644
--- a/drivers/phy/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/phy-rockchip-inno-usb2.c
@@ -165,8 +165,8 @@ static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)
if (ret)
return ret;
- /* waitting for the clk become stable */
- mdelay(1);
+ /* waiting for the clk become stable */
+ usleep_range(1200, 1300);
}
return 0;
--
2.0.0
^ permalink raw reply related
* [PATCH fpga 8/9] fpga socfpga: Use the scatterlist interface
From: Jason Gunthorpe @ 2016-11-15 4:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.10.1611132149140.2908@atull-VirtualBox>
On Sun, Nov 13, 2016 at 10:02:00PM -0600, atull wrote:
> > I'd add a newop 'write_fragment' and a driver must define write_sg
> > write_fragment, if write_fragment is used then the core supplies
> > that loop.
>
> Sure, but isn't that just the old op? :)
I'm fine with that too, but it is semantically different since write
is called multiple times in this new world.. All the drivers seem fine
with that today so it is probably OK ..
> There may also be common code that you added to configure_init
> that should go in the core unless it's fpga-specific.
Sure, the alignment test is easy enough to pull out..
Jason
^ permalink raw reply
* [PATCH 3/3] soc: fsl: make guts driver explicitly non-modular
From: Scott Wood @ 2016-11-15 5:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161113190302.18099-4-paul.gortmaker@windriver.com>
On Sun, 2016-11-13 at 14:03 -0500, Paul Gortmaker wrote:
> The Kconfig currently controlling compilation of this code is:
>
> drivers/soc/fsl/Kconfig:config FSL_GUTS
> drivers/soc/fsl/Kconfig:????????bool
>
> ...meaning that it currently is not being built as a module by anyone.
>
> Lets remove the modular code that is essentially orphaned, so that
> when reading the driver there is no doubt it is builtin-only.
>
> We explicitly disallow a driver unbind, since that doesn't have a
> sensible use case anyway, and it allows us to drop the ".remove"
> code for non-modular drivers.
>
> Since the code was already not using module_init, the init ordering
> remains unchanged with this commit.
>
> Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code.
>
> Cc: Scott Wood <oss@buserror.net>
> Cc: Yangbo Lu <yangbo.lu@nxp.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Ulf Hansson <ulf.hansson@linaro.org>
> Cc: linuxppc-dev at lists.ozlabs.org
> Cc: linux-arm-kernel at lists.infradead.org
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Acked-by: Scott Wood <oss@buserror.net>
-Scott
^ permalink raw reply
* [PATCH v2 2/2] ARM: dts: apq8064: add support to pm8821
From: Bjorn Andersson @ 2016-11-15 5:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479145933-9849-2-git-send-email-srinivas.kandagatla@linaro.org>
On Mon 14 Nov 09:52 PST 2016, Srinivas Kandagatla wrote:
Acked-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Regards,
Bjorn
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
> arch/arm/boot/dts/qcom-apq8064.dtsi | 27 +++++++++++++++++++++++++++
> 1 file changed, 27 insertions(+)
>
> diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
> index 268bd47..c61ba32 100644
> --- a/arch/arm/boot/dts/qcom-apq8064.dtsi
> +++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
> @@ -627,6 +627,33 @@
> clock-names = "core";
> };
>
> + ssbi at c00000 {
> + compatible = "qcom,ssbi";
> + reg = <0x00c00000 0x1000>;
> + qcom,controller-type = "pmic-arbiter";
> +
> + pm8821: pmic at 1 {
> + compatible = "qcom,pm8821";
> + interrupt-parent = <&tlmm_pinmux>;
> + interrupts = <76 IRQ_TYPE_LEVEL_LOW>;
> + #interrupt-cells = <2>;
> + interrupt-controller;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + pm8821_mpps: mpps at 50 {
> + compatible = "qcom,pm8821-mpp", "qcom,ssbi-mpp";
> + reg = <0x50>;
> + interrupts = <24 IRQ_TYPE_NONE>,
> + <25 IRQ_TYPE_NONE>,
> + <26 IRQ_TYPE_NONE>,
> + <27 IRQ_TYPE_NONE>;
> + gpio-controller;
> + #gpio-cells = <2>;
> + };
> + };
> + };
> +
> qcom,ssbi at 500000 {
> compatible = "qcom,ssbi";
> reg = <0x00500000 0x1000>;
> --
> 2.10.1
>
^ permalink raw reply
* [PATCH] arm64: dts: ls1046a: add qdma device tree node
From: H.B. Zhang @ 2016-11-15 5:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479180277-3823-1-git-send-email-hongbo.zhang@nxp.com>
This patch is against the latest linux-next, and the binding file is being upstreamed by the qdma driver author Yuan Yao, so it isn't include in this patch.
> -----Original Message-----
> From: hongbo.zhang at nxp.com [mailto:hongbo.zhang at nxp.com]
> Sent: Tuesday, November 15, 2016 11:25 AM
> To: linux-arm-kernel at lists.infradead.org; Yao Yuan <yao.yuan@nxp.com>;
> shawnguo at kernel.org
> Cc: H.B. Zhang <hongbo.zhang@nxp.com>
> Subject: [PATCH] arm64: dts: ls1046a: add qdma device tree node
>
> From: Hongbo Zhang <hongbo.zhang@nxp.com>
>
> The drivers/dma/fsl-qdma.c works for ls1046a too, this patch adds
> device tree node for it.
>
> Signed-off-by: Hongbo Zhang <hongbo.zhang@nxp.com>
> ---
> arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
> b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
> index 38806ca..6edf7cf 100644
> --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
> @@ -511,5 +511,19 @@
> interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
> clocks = <&clockgen 4 1>;
> };
> +
> + qdma: qdma at 8380000 {
> + compatible = "fsl,ls1046a-qdma", "fsl,ls1021a-qdma";
> + reg = <0x0 0x838f000 0x0 0x11000 /* Controller regs */
> + 0x0 0x83a0000 0x0 0x40000>; /* Block regs */
> + interrupts = <0 152 0x4>,
> + <0 39 0x4>;
> + interrupt-names = "qdma-error", "qdma-queue";
> + channels = <8>;
> + queues = <2>;
> + status-sizes = <64>;
> + queue-sizes = <64 64>;
> + big-endian;
> + };
> };
> };
> --
> 2.1.4
>
^ permalink raw reply
* [PATCH v2 4/6] mm: mempolicy: intruduce a helper huge_nodemask()
From: Aneesh Kumar K.V @ 2016-11-15 6:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479107259-2011-5-git-send-email-shijie.huang@arm.com>
Huang Shijie <shijie.huang@arm.com> writes:
> This patch intruduces a new helper huge_nodemask(),
> we can use it to get the node mask.
>
> This idea of the function is from the huge_zonelist().
>
> Signed-off-by: Huang Shijie <shijie.huang@arm.com>
> ---
> include/linux/mempolicy.h | 8 ++++++++
> mm/mempolicy.c | 20 ++++++++++++++++++++
> 2 files changed, 28 insertions(+)
>
> diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
> index 5e5b296..01173c6 100644
> --- a/include/linux/mempolicy.h
> +++ b/include/linux/mempolicy.h
> @@ -145,6 +145,8 @@ extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
> enum mpol_rebind_step step);
> extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
>
> +extern nodemask_t *huge_nodemask(struct vm_area_struct *vma,
> + unsigned long addr);
> extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
> unsigned long addr, gfp_t gfp_flags,
> struct mempolicy **mpol, nodemask_t **nodemask);
> @@ -261,6 +263,12 @@ static inline void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new)
> {
> }
>
> +static inline nodemask_t *huge_nodemask(struct vm_area_struct *vma,
> + unsigned long addr)
> +{
> + return NULL;
> +}
> +
> static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma,
> unsigned long addr, gfp_t gfp_flags,
> struct mempolicy **mpol, nodemask_t **nodemask)
> diff --git a/mm/mempolicy.c b/mm/mempolicy.c
> index 6d3639e..4830dd6 100644
> --- a/mm/mempolicy.c
> +++ b/mm/mempolicy.c
> @@ -1800,6 +1800,26 @@ static inline unsigned interleave_nid(struct mempolicy *pol,
>
> #ifdef CONFIG_HUGETLBFS
> /*
> + * huge_nodemask(@vma, @addr)
> + * @vma: virtual memory area whose policy is sought
> + * @addr: address in @vma for shared policy lookup and interleave policy
> + *
> + * If the effective policy is BIND, returns a pointer to the mempolicy's
> + * @nodemask.
> + */
> +nodemask_t *huge_nodemask(struct vm_area_struct *vma, unsigned long addr)
> +{
> + nodemask_t *nodes_mask = NULL;
> + struct mempolicy *mpol = get_vma_policy(vma, addr);
> +
> + if (mpol->mode == MPOL_BIND)
> + nodes_mask = &mpol->v.nodes;
> + mpol_cond_put(mpol);
What if it is MPOL_PREFERED or MPOL_INTERLEAVE ? we don't honor node
mask in that case ?
> +
> + return nodes_mask;
> +}
> +
> +/*
> * huge_zonelist(@vma, @addr, @gfp_flags, @mpol)
> * @vma: virtual memory area whose policy is sought
> * @addr: address in @vma for shared policy lookup and interleave policy
> --
> 2.5.5
^ permalink raw reply
* [PATCH v18 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
From: Archit Taneja @ 2016-11-15 6:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479130908-17593-2-git-send-email-jitao.shi@mediatek.com>
Hi,
On 11/14/2016 07:11 PM, Jitao Shi wrote:
> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
Thanks for the incorporating the fixes. I have commented on one issue
below.
The only thing that seems to be left now is the firmware update bits, right?
Can we get the firmware pushed on the linux-firmware git repo [1]?
Or
Remove the firmware update parts for now (including the SPI stuff,
since that seems to be only used for writing fw)?
[1] http://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/
Thanks,
Archit
>
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
> Changes since v17:
> - remove some unused head files.
> - add macros for ps8640 pages.
> - remove ddc_i2c client
> - add mipi_dsi_device_register_full
> - remove the manufacturer from the name and i2c_device_id
>
> Changes since v16:
> - Disable ps8640 DSI MCS Function.
> - Rename gpios name more clearly.
> - Tune the ps8640 power on sequence.
>
> Changes since v15:
> - Drop drm_connector_(un)register calls from parade ps8640.
> The main DRM driver mtk_drm_drv now calls
> drm_connector_register_all() after drm_dev_register() in the
> mtk_drm_bind() function. That function should iterate over all
> connectors and call drm_connector_register() for each of them.
> So, remove drm_connector_(un)register calls from parade ps8640.
>
> Changes since v14:
> - update copyright info.
> - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
> - fix some coding style.
> - use sizeof as array counter.
> - use drm_get_edid when read edid.
> - add mutex when firmware updating.
>
> Changes since v13:
> - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
> - fix PAGE2_SW_REST tyro.
> - move the buf[3] init to entrance of the function.
>
> Changes since v12:
> - fix hw_chip_id build warning
>
> Changes since v11:
> - Remove depends on I2C, add DRM depends
> - Reuse ps8640_write_bytes() in ps8640_write_byte()
> - Use timer check for polling like the routines in <linux/iopoll.h>
> - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
> - Check the ps8640 hardware id in ps8640_validate_firmware
> - Remove fw_version check
> - Move ps8640_validate_firmware before ps8640_enter_bl
> - Add ddc_i2c unregister when probe fail and ps8640_remove
> ---
> drivers/gpu/drm/bridge/Kconfig | 12 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/parade-ps8640.c | 1079 ++++++++++++++++++++++++++++++++
> 3 files changed, 1092 insertions(+)
> create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 10e12e7..7f41bbc 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -57,6 +57,18 @@ config DRM_PARADE_PS8622
> ---help---
> Parade eDP-LVDS bridge chip driver.
>
> +config DRM_PARADE_PS8640
> + tristate "Parade PS8640 MIPI DSI to eDP Converter"
> + depends on DRM
> + depends on OF
> + select DRM_KMS_HELPER
> + select DRM_MIPI_DSI
> + select DRM_PANEL
> + ---help---
> + Choose this option if you have PS8640 for display
> + The PS8640 is a high-performance and low-power
> + MIPI DSI to eDP converter
> +
> config DRM_SII902X
> tristate "Silicon Image sii902x RGB/HDMI bridge"
> depends on OF
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index cdf3a3c..7d93d40 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
> obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
> obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
> obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
> +obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
> obj-$(CONFIG_DRM_SII902X) += sii902x.o
> obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
> obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
> new file mode 100644
> index 0000000..2d9c337
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> @@ -0,0 +1,1079 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/firmware.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of_graph.h>
> +#include <linux/regulator/consumer.h>
> +#include <asm/unaligned.h>
> +#include <drm/drm_panel.h>
> +
> +#include <drmP.h>
> +#include <drm_atomic_helper.h>
> +#include <drm_crtc_helper.h>
> +#include <drm_edid.h>
> +#include <drm_mipi_dsi.h>
> +
> +#define PAGE1_VSTART 0x6b
> +#define PAGE2_SPI_CFG3 0x82
> +#define I2C_TO_SPI_RESET 0x20
> +#define PAGE2_ROMADD_BYTE1 0x8e
> +#define PAGE2_ROMADD_BYTE2 0x8f
> +#define PAGE2_SWSPI_WDATA 0x90
> +#define PAGE2_SWSPI_RDATA 0x91
> +#define PAGE2_SWSPI_LEN 0x92
> +#define PAGE2_SWSPI_CTL 0x93
> +#define TRIGGER_NO_READBACK 0x05
> +#define TRIGGER_READBACK 0x01
> +#define PAGE2_SPI_STATUS 0x9e
> +#define SPI_READY 0x0c
> +#define PAGE2_GPIO_L 0xa6
> +#define PAGE2_GPIO_H 0xa7
> +#define PS_GPIO9 BIT(1)
> +#define PAGE2_IROM_CTRL 0xb0
> +#define IROM_ENABLE 0xc0
> +#define IROM_DISABLE 0x80
> +#define PAGE2_SW_RESET 0xbc
> +#define SPI_SW_RESET BIT(7)
> +#define MPU_SW_RESET BIT(6)
> +#define PAGE2_ENCTLSPI_WR 0xda
> +#define PAGE2_I2C_BYPASS 0xea
> +#define I2C_BYPASS_EN 0xd0
> +#define PAGE2_MCS_EN 0xf3
> +#define MCS_EN BIT(0)
> +#define PAGE3_SET_ADD 0xfe
> +#define PAGE3_SET_VAL 0xff
> +#define VDO_CTL_ADD 0x13
> +#define VDO_DIS 0x18
> +#define VDO_EN 0x1c
> +#define PAGE4_REV_L 0xf0
> +#define PAGE4_REV_H 0xf1
> +#define PAGE4_CHIP_L 0xf2
> +#define PAGE4_CHIP_H 0xf3
> +
> +#define PAGE0_DP_CNTL 0
> +#define PAGE1_VDO_BDG 1
> +#define PAGE2_TOP_CNTL 2
> +#define PAGE3_DSI_CNTL1 3
> +#define PAGE4_MIPI_PHY 4
> +#define PAGE5_VPLL 5
> +#define PAGE6_DSI_CNTL2 6
> +#define PAGE7_SPI_CNTL 7
> +#define MAX_DEVS 0x8
> +
> +/* Firmware */
> +#define PS_FW_NAME "ps864x_fw.bin"
> +
> +#define FW_CHIP_ID_OFFSET 0
> +#define FW_VERSION_OFFSET 2
> +#define EDID_I2C_ADDR 0x50
> +
> +#define WRITE_STATUS_REG_CMD 0x01
> +#define READ_STATUS_REG_CMD 0x05
> +#define BUSY BIT(0)
> +#define CLEAR_ALL_PROTECT 0x00
> +#define BLK_PROTECT_BITS 0x0c
> +#define STATUS_REG_PROTECT BIT(7)
> +#define WRITE_ENABLE_CMD 0x06
> +#define CHIP_ERASE_CMD 0xc7
> +
> +struct ps8640_info {
> + u8 family_id;
> + u8 variant_id;
> + u16 version;
> +};
> +
> +struct ps8640 {
> + struct drm_connector connector;
> + struct drm_bridge bridge;
> + struct edid *edid;
> + struct mipi_dsi_device *dsi;
> + struct i2c_client *page[MAX_DEVS];
> + struct regulator_bulk_data supplies[2];
> + struct drm_panel *panel;
> + struct gpio_desc *gpio_reset;
> + struct gpio_desc *gpio_power_down;
> + struct gpio_desc *gpio_mode_sel;
> + bool enabled;
> +
> + /* firmware file info */
> + struct ps8640_info info;
> + bool in_fw_update;
> + /* for firmware update protect */
> + struct mutex fw_mutex;
> +};
> +
> +static const u8 enc_ctrl_code[6] = { 0xaa, 0x55, 0x50, 0x41, 0x52, 0x44 };
> +static const u8 hw_chip_id[4] = { 0x00, 0x0a, 0x00, 0x30 };
> +
> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
> +{
> + return container_of(e, struct ps8640, bridge);
> +}
> +
> +static inline struct ps8640 *connector_to_ps8640(struct drm_connector *e)
> +{
> + return container_of(e, struct ps8640, connector);
> +}
> +
> +static int ps8640_read(struct i2c_client *client, u8 reg, u8 *data,
> + u16 data_len)
> +{
> + int ret;
> + struct i2c_msg msgs[] = {
> + {
> + .addr = client->addr,
> + .flags = 0,
> + .len = 1,
> + .buf = ®,
> + },
> + {
> + .addr = client->addr,
> + .flags = I2C_M_RD,
> + .len = data_len,
> + .buf = data,
> + }
> + };
> +
> + ret = i2c_transfer(client->adapter, msgs, 2);
> +
> + if (ret == 2)
> + return 0;
> + if (ret < 0)
> + return ret;
> + else
> + return -EIO;
> +}
> +
> +static int ps8640_write_bytes(struct i2c_client *client, const u8 *data,
> + u16 data_len)
> +{
> + int ret;
> + struct i2c_msg msg;
> +
> + msg.addr = client->addr;
> + msg.flags = 0;
> + msg.len = data_len;
> + msg.buf = (u8 *)data;
> +
> + ret = i2c_transfer(client->adapter, &msg, 1);
> + if (ret == 1)
> + return 0;
> + if (ret < 0)
> + return ret;
> + else
> + return -EIO;
> +}
> +
> +static int ps8640_write_byte(struct i2c_client *client, u8 reg, u8 data)
> +{
> + u8 buf[] = { reg, data };
> +
> + return ps8640_write_bytes(client, buf, sizeof(buf));
> +}
> +
> +static void ps8640_get_mcu_fw_version(struct ps8640 *ps_bridge)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE5_VPLL];
> + u8 fw_ver[2];
> +
> + ps8640_read(client, 0x4, fw_ver, sizeof(fw_ver));
> + ps_bridge->info.version = (fw_ver[0] << 8) | fw_ver[1];
> +
> + DRM_INFO_ONCE("ps8640 rom fw version %d.%d\n", fw_ver[0], fw_ver[1]);
> +}
> +
> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> + u8 vdo_ctrl_buf[3] = { PAGE3_SET_ADD, VDO_CTL_ADD, VDO_EN };
> +
> + return ps8640_write_bytes(client, vdo_ctrl_buf, sizeof(vdo_ctrl_buf));
> +}
> +
> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> + u8 vdo_ctrl_buf[3] = { PAGE3_SET_ADD, VDO_CTL_ADD, VDO_DIS };
> +
> + return ps8640_write_bytes(client, vdo_ctrl_buf, sizeof(vdo_ctrl_buf));
> +}
> +
> +static void ps8640_pre_enable(struct drm_bridge *bridge)
> +{
> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> + struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> + struct i2c_client *page1 = ps_bridge->page[PAGE1_VDO_BDG];
> + int err;
> + u8 set_vdo_done, mcs_en, vstart;
> + ktime_t timeout;
> +
> + if (ps_bridge->in_fw_update)
> + return;
> +
> + if (ps_bridge->enabled)
> + return;
> +
> + err = drm_panel_prepare(ps_bridge->panel);
> + if (err < 0) {
> + DRM_ERROR("failed to prepare panel: %d\n", err);
> + return;
> + }
> +
> + err = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
> + ps_bridge->supplies);
> + if (err < 0) {
> + DRM_ERROR("cannot enable regulators %d\n", err);
> + goto err_panel_unprepare;
> + }
> +
> + gpiod_set_value(ps_bridge->gpio_power_down, 1);
> + gpiod_set_value(ps_bridge->gpio_reset, 0);
> + usleep_range(2000, 2500);
> + gpiod_set_value(ps_bridge->gpio_reset, 1);
> +
> + /*
> + * Wait for the ps8640 embed mcu ready
> + * First wait 200ms and then check the mcu ready flag every 20ms
> + */
> + msleep(200);
> +
> + timeout = ktime_add_ms(ktime_get(), 200);
> + for (;;) {
> + err = ps8640_read(client, PAGE2_GPIO_H, &set_vdo_done, 1);
> + if (err < 0) {
> + DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", err);
> + goto err_regulators_disable;
> + }
> + if ((set_vdo_done & PS_GPIO9) == PS_GPIO9)
> + break;
> + if (ktime_compare(ktime_get(), timeout) > 0)
> + break;
> + msleep(20);
> + }
> +
> + msleep(50);
> +
> + ps8640_read(page1, PAGE1_VSTART, &vstart, 1);
> + DRM_INFO("PS8640 PAGE1.0x6B = 0x%x\n", vstart);
> +
> + /**
> + * The Manufacturer Command Set (MCS) is a device dependent interface
> + * intended for factory programming of the display module default
> + * parameters. Once the display module is configured, the MCS shall be
> + * disabled by the manufacturer. Once disabled, all MCS commands are
> + * ignored by the display interface.
> + */
> + ps8640_read(client, PAGE2_MCS_EN, &mcs_en, 1);
> + ps8640_write_byte(client, PAGE2_MCS_EN, mcs_en & ~MCS_EN);
> +
> + if (ps_bridge->info.version == 0)
> + ps8640_get_mcu_fw_version(ps_bridge);
> +
> + err = ps8640_bridge_unmute(ps_bridge);
> + if (err)
> + DRM_ERROR("failed to enable unmutevideo: %d\n", err);
> + /* Switch access edp panel's edid through i2c */
> + ps8640_write_byte(client, PAGE2_I2C_BYPASS, I2C_BYPASS_EN);
> + ps_bridge->enabled = true;
> +
> + return;
> +
> +err_regulators_disable:
> + regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> + ps_bridge->supplies);
> +err_panel_unprepare:
> + drm_panel_unprepare(ps_bridge->panel);
> +}
> +
> +static void ps8640_enable(struct drm_bridge *bridge)
> +{
> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> + int err;
> +
> + err = drm_panel_enable(ps_bridge->panel);
> + if (err < 0)
> + DRM_ERROR("failed to enable panel: %d\n", err);
> +}
> +
> +static void ps8640_disable(struct drm_bridge *bridge)
> +{
> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> + int err;
> +
> + err = drm_panel_disable(ps_bridge->panel);
> + if (err < 0)
> + DRM_ERROR("failed to disable panel: %d\n", err);
> +}
> +
> +static void ps8640_post_disable(struct drm_bridge *bridge)
> +{
> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> + int err;
> +
> + if (ps_bridge->in_fw_update)
> + return;
> +
> + if (!ps_bridge->enabled)
> + return;
> +
> + ps_bridge->enabled = false;
> +
> + err = ps8640_bridge_mute(ps_bridge);
> + if (err < 0)
> + DRM_ERROR("failed to unmutevideo: %d\n", err);
> +
> + gpiod_set_value(ps_bridge->gpio_reset, 0);
> + gpiod_set_value(ps_bridge->gpio_power_down, 0);
> + err = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> + ps_bridge->supplies);
> + if (err < 0)
> + DRM_ERROR("cannot disable regulators %d\n", err);
> +
> + err = drm_panel_unprepare(ps_bridge->panel);
> + if (err)
> + DRM_ERROR("failed to unprepare panel: %d\n", err);
> +}
> +
> +static int ps8640_get_modes(struct drm_connector *connector)
> +{
> + struct ps8640 *ps_bridge = connector_to_ps8640(connector);
> + struct edid *edid;
> + int num_modes = 0;
> + bool power_off;
> +
> + if (ps_bridge->edid)
> + return drm_add_edid_modes(connector, ps_bridge->edid);
> +
> + power_off = !ps_bridge->enabled;
> + ps8640_pre_enable(&ps_bridge->bridge);
> +
> + edid = drm_get_edid(connector, ps_bridge->page[0]->adapter);
> + if (!edid)
> + goto out;
> +
> + ps_bridge->edid = edid;
> + drm_mode_connector_update_edid_property(connector, ps_bridge->edid);
> + num_modes = drm_add_edid_modes(connector, ps_bridge->edid);
> +
> +out:
> + if (power_off)
> + ps8640_post_disable(&ps_bridge->bridge);
> +
> + return num_modes;
> +}
> +
> +static const struct drm_connector_helper_funcs ps8640_connector_helper_funcs = {
> + .get_modes = ps8640_get_modes,
> +};
> +
> +static enum drm_connector_status ps8640_detect(struct drm_connector *connector,
> + bool force)
> +{
> + return connector_status_connected;
> +}
> +
> +static const struct drm_connector_funcs ps8640_connector_funcs = {
> + .dpms = drm_atomic_helper_connector_dpms,
> + .fill_modes = drm_helper_probe_single_connector_modes,
> + .detect = ps8640_detect,
> + .reset = drm_atomic_helper_connector_reset,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +int ps8640_bridge_attach(struct drm_bridge *bridge)
> +{
> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> + struct device *dev = &ps_bridge->page[0]->dev;
> + struct device_node *in_ep, *dsi_node = NULL;
> + struct mipi_dsi_device *dsi;
> + struct mipi_dsi_host *host = NULL;
> + int ret;
> + const struct mipi_dsi_device_info info = { .type = "ps8640",
> + .channel = 0,
> + .node = NULL,
> + };
> +
> + ret = drm_connector_init(bridge->dev, &ps_bridge->connector,
> + &ps8640_connector_funcs,
> + DRM_MODE_CONNECTOR_eDP);
> +
> + if (ret) {
> + DRM_ERROR("Failed to initialize connector with drm: %d\n", ret);
> + return ret;
> + }
> +
> + drm_connector_helper_add(&ps_bridge->connector,
> + &ps8640_connector_helper_funcs);
> +
> + ps_bridge->connector.dpms = DRM_MODE_DPMS_ON;
> + drm_mode_connector_attach_encoder(&ps_bridge->connector,
> + bridge->encoder);
> +
> + if (ps_bridge->panel)
> + drm_panel_attach(ps_bridge->panel, &ps_bridge->connector);
> +
> + /* port at 0 is ps8640 dsi input port */
> + in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
> + if (in_ep) {
> + dsi_node = of_graph_get_remote_port_parent(in_ep);
> + of_node_put(in_ep);
> + }
> +
> + if (dsi_node) {
> + host = of_find_mipi_dsi_host_by_node(dsi_node);
> + of_node_put(dsi_node);
> + if (!host) {
> + ret = -ENODEV;
> + goto err;
> + }
> + }
There's still a possibility of us trying to register the dsi
device here to a null host.
Suggested code:
in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
if (!in_ep) {
ret = -ENODEV;
goto err;
}
dsi_node = of_graph_get_remote_port_parent(in_ep);
if (!dsi_node) {
of_node_put(in_ep);
ret = -ENODEV;
goto err;
}
of_node_put(in_ep);
of_node_put(dsi_node);
host = of_find_mipi_dsi_host_by_node(dsi_node);
if (!host) {
ret = -EPROBE_DEFER;
goto err;
}
Thanks,
Archit
> +
> + dsi = mipi_dsi_device_register_full(host, &info);
> + if (IS_ERR(dsi)) {
> + dev_err(dev, "failed to create dsi device\n");
> + ret = PTR_ERR(dsi);
> + goto err;
> + }
> +
> + ps_bridge->dsi = dsi;
> +
> + dsi->host = host;
> + dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
> + MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> + dsi->format = MIPI_DSI_FMT_RGB888;
> + dsi->lanes = 4;
> + ret = mipi_dsi_attach(dsi);
> + if (ret)
> + goto err_dsi_attach;
> +
> + return 0;
> +
> +err_dsi_attach:
> + mipi_dsi_device_unregister(dsi);
> +err:
> + if (ps_bridge->panel)
> + drm_panel_detach(ps_bridge->panel);
> + drm_connector_cleanup(&ps_bridge->connector);
> + return ret;
> +}
> +
> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
> + .attach = ps8640_bridge_attach,
> + .disable = ps8640_disable,
> + .post_disable = ps8640_post_disable,
> + .pre_enable = ps8640_pre_enable,
> + .enable = ps8640_enable,
> +};
> +
> +/* Firmware Version is returned as Major.Minor */
> +static ssize_t ps8640_fw_version_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct ps8640 *ps_bridge = dev_get_drvdata(dev);
> + struct ps8640_info *info = &ps_bridge->info;
> +
> + return scnprintf(buf, PAGE_SIZE, "%u.%u\n", info->version >> 8,
> + info->version & 0xff);
> +}
> +
> +/* Hardware Version is returned as FamilyID.VariantID */
> +static ssize_t ps8640_hw_version_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct ps8640 *ps_bridge = dev_get_drvdata(dev);
> + struct ps8640_info *info = &ps_bridge->info;
> +
> + return scnprintf(buf, PAGE_SIZE, "ps%u.%u\n", info->family_id,
> + info->variant_id);
> +}
> +
> +static int ps8640_spi_send_cmd(struct ps8640 *ps_bridge, u8 *cmd, u8 cmd_len)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> + u8 i, buf[3] = { PAGE2_SWSPI_LEN, cmd_len - 1, TRIGGER_NO_READBACK };
> + int ret;
> +
> + ret = ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_ENABLE);
> + if (ret)
> + goto err;
> +
> + /* write command in write port */
> + for (i = 0; i < cmd_len; i++) {
> + ret = ps8640_write_byte(client, PAGE2_SWSPI_WDATA, cmd[i]);
> + if (ret)
> + goto err_irom_disable;
> + }
> +
> + ret = ps8640_write_bytes(client, buf, sizeof(buf));
> + if (ret)
> + goto err_irom_disable;
> +
> + ret = ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
> + if (ret)
> + goto err;
> +
> + return 0;
> +err_irom_disable:
> + ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
> +err:
> + dev_err(&client->dev, "send command err: %d\n", ret);
> + return ret;
> +}
> +
> +static int ps8640_wait_spi_ready(struct ps8640 *ps_bridge)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> + u8 spi_rdy_st;
> + ktime_t timeout;
> +
> + timeout = ktime_add_ms(ktime_get(), 200);
> + for (;;) {
> + ps8640_read(client, PAGE2_SPI_STATUS, &spi_rdy_st, 1);
> + if ((spi_rdy_st & SPI_READY) != SPI_READY)
> + break;
> +
> + if (ktime_compare(ktime_get(), timeout) > 0) {
> + dev_err(&client->dev, "wait spi ready timeout\n");
> + return -EBUSY;
> + }
> +
> + msleep(20);
> + }
> +
> + return 0;
> +}
> +
> +static int ps8640_wait_spi_nobusy(struct ps8640 *ps_bridge)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> + u8 spi_status, buf[3] = { PAGE2_SWSPI_LEN, 0, TRIGGER_READBACK };
> + int ret;
> + ktime_t timeout;
> +
> + timeout = ktime_add_ms(ktime_get(), 500);
> + for (;;) {
> + /* 0x05 RDSR; Read-Status-Register */
> + ret = ps8640_write_byte(client, PAGE2_SWSPI_WDATA,
> + READ_STATUS_REG_CMD);
> + if (ret)
> + goto err_send_cmd_exit;
> +
> + ret = ps8640_write_bytes(client, buf, 3);
> + if (ret)
> + goto err_send_cmd_exit;
> +
> + /* delay for cmd send */
> + usleep_range(300, 500);
> + /* wait for SPI ROM until not busy */
> + ret = ps8640_read(client, PAGE2_SWSPI_RDATA, &spi_status, 1);
> + if (ret)
> + goto err_send_cmd_exit;
> +
> + if (!(spi_status & BUSY))
> + break;
> +
> + if (ktime_compare(ktime_get(), timeout) > 0) {
> + dev_err(&client->dev, "wait spi no busy timeout: %d\n",
> + ret);
> + return -EBUSY;
> + }
> + }
> +
> + return 0;
> +
> +err_send_cmd_exit:
> + dev_err(&client->dev, "send command err: %d\n", ret);
> + return ret;
> +}
> +
> +static int ps8640_wait_rom_idle(struct ps8640 *ps_bridge)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE0_DP_CNTL];
> + int ret;
> +
> + ret = ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_ENABLE);
> + if (ret)
> + goto exit;
> +
> + ret = ps8640_wait_spi_ready(ps_bridge);
> + if (ret)
> + goto err_spi;
> +
> + ret = ps8640_wait_spi_nobusy(ps_bridge);
> + if (ret)
> + goto err_spi;
> +
> + ret = ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
> + if (ret)
> + goto exit;
> +
> + return 0;
> +
> +err_spi:
> + ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
> +exit:
> + dev_err(&client->dev, "wait ps8640 rom idle fail: %d\n", ret);
> +
> + return ret;
> +}
> +
> +static int ps8640_spi_dl_mode(struct ps8640 *ps_bridge)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> + int ret;
> +
> + /* switch ps8640 mode to spi dl mode */
> + if (ps_bridge->gpio_mode_sel)
> + gpiod_set_value(ps_bridge->gpio_mode_sel, 0);
> +
> + /* reset spi interface */
> + ret = ps8640_write_byte(client, PAGE2_SW_RESET,
> + SPI_SW_RESET | MPU_SW_RESET);
> + if (ret)
> + goto exit;
> +
> + ret = ps8640_write_byte(client, PAGE2_SW_RESET, MPU_SW_RESET);
> + if (ret)
> + goto exit;
> +
> + return 0;
> +
> +exit:
> + dev_err(&client->dev, "fail reset spi interface: %d\n", ret);
> +
> + return ret;
> +}
> +
> +static int ps8640_rom_prepare(struct ps8640 *ps_bridge)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> + struct device *dev = &client->dev;
> + u8 i, cmd[2];
> + int ret;
> +
> + cmd[0] = WRITE_ENABLE_CMD;
> + ret = ps8640_spi_send_cmd(ps_bridge, cmd, 1);
> + if (ret) {
> + dev_err(dev, "failed enable-write-status-register: %d\n", ret);
> + return ret;
> + }
> +
> + cmd[0] = WRITE_STATUS_REG_CMD;
> + cmd[1] = CLEAR_ALL_PROTECT;
> + ret = ps8640_spi_send_cmd(ps_bridge, cmd, 2);
> + if (ret) {
> + dev_err(dev, "fail disable all protection: %d\n", ret);
> + return ret;
> + }
> +
> + /* wait for SPI module ready */
> + ret = ps8640_wait_rom_idle(ps_bridge);
> + if (ret) {
> + dev_err(dev, "fail wait rom idle: %d\n", ret);
> + return ret;
> + }
> +
> + ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_ENABLE);
> + for (i = 0; i < ARRAY_SIZE(enc_ctrl_code); i++)
> + ps8640_write_byte(client, PAGE2_ENCTLSPI_WR, enc_ctrl_code[i]);
> + ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
> +
> + /* Enable-Write-Status-Register */
> + cmd[0] = WRITE_ENABLE_CMD;
> + ret = ps8640_spi_send_cmd(ps_bridge, cmd, 1);
> + if (ret) {
> + dev_err(dev, "fail enable-write-status-register: %d\n", ret);
> + return ret;
> + }
> +
> + /* chip erase command */
> + cmd[0] = CHIP_ERASE_CMD;
> + ret = ps8640_spi_send_cmd(ps_bridge, cmd, 1);
> + if (ret) {
> + dev_err(dev, "fail disable all protection: %d\n", ret);
> + return ret;
> + }
> +
> + ret = ps8640_wait_rom_idle(ps_bridge);
> + if (ret) {
> + dev_err(dev, "fail wait rom idle: %d\n", ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int ps8640_check_chip_id(struct ps8640 *ps_bridge)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE4_MIPI_PHY];
> + u8 buf[4];
> +
> + ps8640_read(client, PAGE4_REV_L, buf, 4);
> + return memcmp(buf, hw_chip_id, sizeof(buf));
> +}
> +
> +static int ps8640_validate_firmware(struct ps8640 *ps_bridge,
> + const struct firmware *fw)
> +{
> + struct i2c_client *client = ps_bridge->page[0];
> + u16 fw_chip_id;
> +
> + /*
> + * Get the chip_id from the firmware. Make sure that it is the
> + * right controller to do the firmware and config update.
> + */
> + fw_chip_id = get_unaligned_le16(fw->data + FW_CHIP_ID_OFFSET);
> +
> + if (fw_chip_id != 0x8640 && ps8640_check_chip_id(ps_bridge) == 0) {
> + dev_err(&client->dev,
> + "chip id mismatch: fw 0x%x vs. chip 0x8640\n",
> + fw_chip_id);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int ps8640_write_rom(struct ps8640 *ps_bridge, const struct firmware *fw)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE0_DP_CNTL];
> + struct device *dev = &client->dev;
> + struct i2c_client *client2 = ps_bridge->page[PAGE2_TOP_CNTL];
> + struct i2c_client *client7 = ps_bridge->page[PAGE7_SPI_CNTL];
> + size_t pos, cpy_len;
> + u8 buf[257];
> + int ret;
> +
> + ps8640_write_byte(client2, PAGE2_SPI_CFG3, I2C_TO_SPI_RESET);
> + msleep(100);
> + ps8640_write_byte(client2, PAGE2_SPI_CFG3, 0x00);
> +
> + for (pos = 0; pos < fw->size; pos += cpy_len) {
> + buf[0] = PAGE2_ROMADD_BYTE1;
> + buf[1] = pos >> 8;
> + buf[2] = pos >> 16;
> + ret = ps8640_write_bytes(client2, buf, 3);
> + if (ret)
> + goto error;
> + cpy_len = fw->size >= 256 + pos ? 256 : fw->size - pos;
> + buf[0] = 0;
> + memcpy(buf + 1, fw->data + pos, cpy_len);
> + ret = ps8640_write_bytes(client7, buf, cpy_len + 1);
> + if (ret)
> + goto error;
> +
> + dev_dbg(dev, "fw update completed %zu / %zu bytes\n", pos,
> + fw->size);
> + }
> + return 0;
> +
> +error:
> + dev_err(dev, "failed write external flash, %d\n", ret);
> + return ret;
> +}
> +
> +static int ps8640_spi_normal_mode(struct ps8640 *ps_bridge)
> +{
> + u8 cmd[2];
> + struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> +
> + /* Enable-Write-Status-Register */
> + cmd[0] = WRITE_ENABLE_CMD;
> + ps8640_spi_send_cmd(ps_bridge, cmd, 1);
> +
> + /* protect BPL/BP0/BP1 */
> + cmd[0] = WRITE_STATUS_REG_CMD;
> + cmd[1] = BLK_PROTECT_BITS | STATUS_REG_PROTECT;
> + ps8640_spi_send_cmd(ps_bridge, cmd, 2);
> +
> + /* wait for SPI rom ready */
> + ps8640_wait_rom_idle(ps_bridge);
> +
> + /* disable PS8640 mapping function */
> + ps8640_write_byte(client, PAGE2_ENCTLSPI_WR, 0x00);
> +
> + if (ps_bridge->gpio_mode_sel)
> + gpiod_set_value(ps_bridge->gpio_mode_sel, 1);
> + return 0;
> +}
> +
> +static int ps8640_enter_bl(struct ps8640 *ps_bridge)
> +{
> + ps_bridge->in_fw_update = true;
> + return ps8640_spi_dl_mode(ps_bridge);
> +}
> +
> +static void ps8640_exit_bl(struct ps8640 *ps_bridge, const struct firmware *fw)
> +{
> + ps8640_spi_normal_mode(ps_bridge);
> + ps_bridge->in_fw_update = false;
> +}
> +
> +static int ps8640_load_fw(struct ps8640 *ps_bridge, const struct firmware *fw)
> +{
> + struct i2c_client *client = ps_bridge->page[PAGE0_DP_CNTL];
> + struct device *dev = &client->dev;
> + int ret;
> + bool ps8640_status_backup = ps_bridge->enabled;
> +
> + ret = ps8640_validate_firmware(ps_bridge, fw);
> + if (ret)
> + return ret;
> +
> + mutex_lock(&ps_bridge->fw_mutex);
> + if (!ps_bridge->in_fw_update) {
> + if (!ps8640_status_backup)
> + ps8640_pre_enable(&ps_bridge->bridge);
> +
> + ret = ps8640_enter_bl(ps_bridge);
> + if (ret)
> + goto exit;
> + }
> +
> + ret = ps8640_rom_prepare(ps_bridge);
> + if (ret)
> + goto exit;
> +
> + ret = ps8640_write_rom(ps_bridge, fw);
> +
> +exit:
> + if (ret)
> + dev_err(dev, "Failed to load firmware, %d\n", ret);
> +
> + ps8640_exit_bl(ps_bridge, fw);
> + if (!ps8640_status_backup)
> + ps8640_post_disable(&ps_bridge->bridge);
> + mutex_unlock(&ps_bridge->fw_mutex);
> + return ret;
> +}
> +
> +static ssize_t ps8640_update_fw_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct i2c_client *client = to_i2c_client(dev);
> + struct ps8640 *ps_bridge = i2c_get_clientdata(client);
> + const struct firmware *fw;
> + int error;
> +
> + error = request_firmware(&fw, PS_FW_NAME, dev);
> + if (error) {
> + dev_err(dev, "Unable to open firmware %s: %d\n",
> + PS_FW_NAME, error);
> + return error;
> + }
> +
> + error = ps8640_load_fw(ps_bridge, fw);
> + if (error)
> + dev_err(dev, "The firmware update failed(%d)\n", error);
> + else
> + dev_info(dev, "The firmware update succeeded\n");
> +
> + release_firmware(fw);
> + return error ? error : count;
> +}
> +
> +static DEVICE_ATTR(fw_version, S_IRUGO, ps8640_fw_version_show, NULL);
> +static DEVICE_ATTR(hw_version, S_IRUGO, ps8640_hw_version_show, NULL);
> +static DEVICE_ATTR(update_fw, S_IWUSR, NULL, ps8640_update_fw_store);
> +
> +static struct attribute *ps8640_attrs[] = {
> + &dev_attr_fw_version.attr,
> + &dev_attr_hw_version.attr,
> + &dev_attr_update_fw.attr,
> + NULL
> +};
> +
> +static const struct attribute_group ps8640_attr_group = {
> + .attrs = ps8640_attrs,
> +};
> +
> +static void ps8640_remove_sysfs_group(void *data)
> +{
> + struct ps8640 *ps_bridge = data;
> +
> + sysfs_remove_group(&ps_bridge->page[0]->dev.kobj, &ps8640_attr_group);
> +}
> +
> +static int ps8640_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct device *dev = &client->dev;
> + struct ps8640 *ps_bridge;
> + struct device_node *np = dev->of_node;
> + struct device_node *port, *out_ep;
> + struct device_node *panel_node = NULL;
> + int ret;
> + u32 i;
> +
> + ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
> + if (!ps_bridge)
> + return -ENOMEM;
> +
> + /* port at 1 is ps8640 output port */
> + port = of_graph_get_port_by_id(np, 1);
> + if (port) {
> + out_ep = of_get_child_by_name(port, "endpoint");
> + of_node_put(port);
> + if (out_ep) {
> + panel_node = of_graph_get_remote_port_parent(out_ep);
> + of_node_put(out_ep);
> + }
> + }
> + if (panel_node) {
> + ps_bridge->panel = of_drm_find_panel(panel_node);
> + of_node_put(panel_node);
> + if (!ps_bridge->panel)
> + return -EPROBE_DEFER;
> + }
> +
> + mutex_init(&ps_bridge->fw_mutex);
> + ps_bridge->supplies[0].supply = "vdd33";
> + ps_bridge->supplies[1].supply = "vdd12";
> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
> + ps_bridge->supplies);
> + if (ret) {
> + dev_info(dev, "failed to get regulators: %d\n", ret);
> + return ret;
> + }
> +
> + ps_bridge->gpio_mode_sel = devm_gpiod_get_optional(&client->dev,
> + "mode-sel",
> + GPIOD_OUT_HIGH);
> + if (IS_ERR(ps_bridge->gpio_mode_sel)) {
> + ret = PTR_ERR(ps_bridge->gpio_mode_sel);
> + dev_err(dev, "cannot get mode-sel %d\n", ret);
> + return ret;
> + }
> +
> + ps_bridge->gpio_power_down = devm_gpiod_get(&client->dev, "sleep",
> + GPIOD_OUT_LOW);
> + if (IS_ERR(ps_bridge->gpio_power_down)) {
> + ret = PTR_ERR(ps_bridge->gpio_power_down);
> + dev_err(dev, "cannot get sleep: %d\n", ret);
> + return ret;
> + }
> +
> + /*
> + * Request the reset pin low to avoid the bridge being
> + * initialized prematurely
> + */
> + ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
> + GPIOD_OUT_LOW);
> + if (IS_ERR(ps_bridge->gpio_reset)) {
> + ret = PTR_ERR(ps_bridge->gpio_reset);
> + dev_err(dev, "cannot get reset: %d\n", ret);
> + return ret;
> + }
> +
> + ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
> + ps_bridge->bridge.of_node = dev->of_node;
> +
> + ps_bridge->page[0] = client;
> +
> + /*
> + * ps8640 uses multiple addresses, use dummy devices for them
> + * page[0]: for DP control
> + * page[1]: for VIDEO Bridge
> + * page[2]: for control top
> + * page[3]: for DSI Link Control1
> + * page[4]: for MIPI Phy
> + * page[5]: for VPLL
> + * page[6]: for DSI Link Control2
> + * page[7]: for spi rom mapping
> + */
> + for (i = 1; i < MAX_DEVS; i++) {
> + ps_bridge->page[i] = i2c_new_dummy(client->adapter,
> + client->addr + i);
> + if (!ps_bridge->page[i]) {
> + dev_err(dev, "failed i2c dummy device, address%02x\n",
> + client->addr + i);
> + ret = -EBUSY;
> + goto exit_dummy;
> + }
> + }
> + i2c_set_clientdata(client, ps_bridge);
> +
> + ret = sysfs_create_group(&client->dev.kobj, &ps8640_attr_group);
> + if (ret) {
> + dev_err(dev, "failed to create sysfs entries: %d\n", ret);
> + goto exit_dummy;
> + }
> +
> + ret = devm_add_action(dev, ps8640_remove_sysfs_group, ps_bridge);
> + if (ret) {
> + dev_err(dev, "failed to add sysfs cleanup action: %d\n", ret);
> + goto exit_remove_sysfs;
> + }
> +
> + ret = drm_bridge_add(&ps_bridge->bridge);
> + if (ret) {
> + dev_err(dev, "Failed to add bridge: %d\n", ret);
> + goto exit_remove_sysfs;
> + }
> + return 0;
> +
> +exit_remove_sysfs:
> + sysfs_remove_group(&ps_bridge->page[0]->dev.kobj, &ps8640_attr_group);
> +exit_dummy:
> + while (--i)
> + i2c_unregister_device(ps_bridge->page[i]);
> + return ret;
> +}
> +
> +static int ps8640_remove(struct i2c_client *client)
> +{
> + struct ps8640 *ps_bridge = i2c_get_clientdata(client);
> + int i = MAX_DEVS;
> +
> + drm_bridge_remove(&ps_bridge->bridge);
> + sysfs_remove_group(&ps_bridge->page[0]->dev.kobj, &ps8640_attr_group);
> + while (--i)
> + i2c_unregister_device(ps_bridge->page[i]);
> +
> + return 0;
> +}
> +
> +static const struct i2c_device_id ps8640_i2c_table[] = {
> + { "ps8640", 0 },
> + { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(i2c, ps8640_i2c_table);
> +
> +static const struct of_device_id ps8640_match[] = {
> + { .compatible = "parade,ps8640" },
> + { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, ps8640_match);
> +
> +static struct i2c_driver ps8640_driver = {
> + .id_table = ps8640_i2c_table,
> + .probe = ps8640_probe,
> + .remove = ps8640_remove,
> + .driver = {
> + .name = "ps8640",
> + .of_match_table = ps8640_match,
> + },
> +};
> +module_i2c_driver(ps8640_driver);
> +
> +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
> +MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
> +MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
> +MODULE_LICENSE("GPL v2");
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH] arm64: Add DTS support for FSL's LS1012A SoC
From: Harninder Rai @ 2016-11-15 6:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161114071308.GL3310@dragon>
> > dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb
> > dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb
> > dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb
>
> It seems that the patch is not generated against mainline kernel. We do not
> have fsl-ls1046a-qds.dtb target in mainline kernel.
You already clarified in the following mail :)
> > +
> > + reg_1p8v: regulator at 0 {
>
> Drop the unit-address from node name, and name it like regulator-1p8v.
Ok. Will take care in V2
> > +
> > +&duart0 {
>
> Please sort labeled nodes alphabetically.
Ok Sure
>
> > + status = "okay";
> > +};
> > +
> > +&sai2 {
> > + status = "okay";
> > +};
>
> <snip>
>
> > diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
> > b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
> > new file mode 100644
> > index 0000000..0bf5b64
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
> > @@ -0,0 +1,248 @@
> > +/*
> > + * Device Tree Include file for Freescale Layerscape-1012A family SoC.
> > + *
> > + * Copyright 2016, Freescale Semiconductor
> > + *
> > + * This file is dual-licensed: you can use it either under the terms
> > + * of the GPLv2 or the X11 license, at your option. Note that this
> > +dual
> > + * licensing only applies to this file, and not this project as a
> > + * whole.
> > + *
> > + * a) This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation; either version 2 of the
> > + * License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * Or, alternatively,
> > + *
> > + * b) Permission is hereby granted, free of charge, to any person
> > + * obtaining a copy of this software and associated documentation
> > + * files (the "Software"), to deal in the Software without
> > + * restriction, including without limitation the rights to use,
> > + * copy, modify, merge, publish, distribute, sublicense, and/or
> > + * sell copies of the Software, and to permit persons to whom the
> > + * Software is furnished to do so, subject to the following
> > + * conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be
> > + * included in all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
> KIND,
> > + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
> WARRANTIES
> > + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> > + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
> COPYRIGHT
> > + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> > + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> OR
> > + * OTHER DEALINGS IN THE SOFTWARE.
> > + */
> > +
> > +#include <dt-bindings/interrupt-controller/irq.h>
> > +
> > +/ {
> > + compatible = "fsl,ls1012a";
> > + interrupt-parent = <&gic>;
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > +
> > + cpus {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + cpu0: cpu at 0 {
> > + device_type = "cpu";
> > + compatible = "arm,cortex-a53";
> > + reg = <0x0>;
> > + clocks = <&clockgen 1 0>;
> > + #cooling-cells = <2>;
> > + };
> > + };
> > +
> > + sysclk: sysclk {
> > + compatible = "fixed-clock";
> > + #clock-cells = <0>;
> > + clock-frequency = <100000000>;
> > + clock-output-names = "sysclk";
> > + };
> > +
> > + timer {
> > + compatible = "arm,armv8-timer";
> > + /* Physical Secure PPI */
> > + interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>,
> > + /* Physical Non-Secure PPI */
> > + <1 14 IRQ_TYPE_LEVEL_LOW>,
> > + /* Virtual PPI */
> > + <1 11 IRQ_TYPE_LEVEL_LOW>,
> > + /* Hypervisor PPI */
> > + <1 10 IRQ_TYPE_LEVEL_LOW>;
>
> The following form should be easier for read.
>
> interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>, /* Physical Secure
> PPI */
> <1 14 IRQ_TYPE_LEVEL_LOW>, /* Physical Non-
> Secure PPI */
> <1 11 IRQ_TYPE_LEVEL_LOW>, /* Virtual PPI */
> <1 10 IRQ_TYPE_LEVEL_LOW>; /* Hypervisor PPI
> */
>
>
Agreed. My bad. Will correct in v2
> > + };
> > +
> > + pmu {
> > + compatible = "arm,armv8-pmuv3";
> > + interrupts = <0 106 IRQ_TYPE_LEVEL_LOW>;
> > + };
> > +
> > + gic: interrupt-controller at 1400000 {
> > + compatible = "arm,gic-400";
> > + #interrupt-cells = <3>;
> > + interrupt-controller;
> > + reg = <0x0 0x1401000 0 0x1000>, /* GICD */
> > + <0x0 0x1402000 0 0x2000>, /* GICC */
> > + <0x0 0x1404000 0 0x2000>, /* GICH */
> > + <0x0 0x1406000 0 0x2000>; /* GICV */
> > + interrupts = <1 9 IRQ_TYPE_LEVEL_LOW>;
> > + };
> > +
> > + reboot {
> > + compatible = "syscon-reboot";
> > + regmap = <&dcfg>;
> > + offset = <0xb0>;
> > + mask = <0x02>;
> > + };
> > +
> > + soc {
> > + compatible = "simple-bus";
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > + ranges;
> > +
> > + clockgen: clocking at 1ee1000 {
> > + compatible = "fsl,ls1012a-clockgen";
> > + reg = <0x0 0x1ee1000 0x0 0x1000>;
> > + #clock-cells = <2>;
> > + clocks = <&sysclk>;
> > + };
> > +
> > + scfg: scfg at 1570000 {
> > + compatible = "fsl,ls1012a-scfg", "syscon";
> > + reg = <0x0 0x1570000 0x0 0x10000>;
> > + big-endian;
> > + };
>
> Please sort these nodes with unit-address in order of the address.
>
> Shawn
>
> > +
> > + dcfg: dcfg at 1ee0000 {
> > + compatible = "fsl,ls1012a-dcfg",
> > + "syscon";
> > + reg = <0x0 0x1ee0000 0x0 0x10000>;
> > + big-endian;
> > + };
> > +
> > + i2c0: i2c at 2180000 {
> > + compatible = "fsl,vf610-i2c";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + reg = <0x0 0x2180000 0x0 0x10000>;
> > + interrupts = <0 56 IRQ_TYPE_LEVEL_LOW>;
> > + clocks = <&clockgen 4 0>;
> > + status = "disabled";
> > + };
> > +
> > + i2c1: i2c at 2190000 {
> > + compatible = "fsl,vf610-i2c";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + reg = <0x0 0x2190000 0x0 0x10000>;
> > + interrupts = <0 57 IRQ_TYPE_LEVEL_LOW>;
> > + clocks = <&clockgen 4 0>;
> > + status = "disabled";
> > + };
> > +
> > + duart0: serial at 21c0500 {
> > + compatible = "fsl,ns16550", "ns16550a";
> > + reg = <0x00 0x21c0500 0x0 0x100>;
> > + interrupts = <0 54 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&clockgen 4 0>;
> > + };
> > +
> > + duart1: serial at 21c0600 {
> > + compatible = "fsl,ns16550", "ns16550a";
> > + reg = <0x00 0x21c0600 0x0 0x100>;
> > + interrupts = <0 54 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&clockgen 4 0>;
> > + };
> > +
> > + gpio0: gpio at 2300000 {
> > + compatible = "fsl,qoriq-gpio";
> > + reg = <0x0 0x2300000 0x0 0x10000>;
> > + interrupts = <0 66 IRQ_TYPE_LEVEL_LOW>;
> > + gpio-controller;
> > + #gpio-cells = <2>;
> > + interrupt-controller;
> > + #interrupt-cells = <2>;
> > + };
> > +
> > + gpio1: gpio at 2310000 {
> > + compatible = "fsl,qoriq-gpio";
> > + reg = <0x0 0x2310000 0x0 0x10000>;
> > + interrupts = <0 67 IRQ_TYPE_LEVEL_LOW>;
> > + gpio-controller;
> > + #gpio-cells = <2>;
> > + interrupt-controller;
> > + #interrupt-cells = <2>;
> > + };
> > +
> > + wdog0: wdog at 2ad0000 {
> > + compatible = "fsl,ls1012a-wdt",
> > + "fsl,imx21-wdt";
> > + reg = <0x0 0x2ad0000 0x0 0x10000>;
> > + interrupts = <0 83 IRQ_TYPE_LEVEL_LOW>;
> > + clocks = <&clockgen 4 0>;
> > + big-endian;
> > + };
> > +
> > + sai1: sai at 2b50000 {
> > + #sound-dai-cells = <0>;
> > + compatible = "fsl,vf610-sai";
> > + reg = <0x0 0x2b50000 0x0 0x10000>;
> > + interrupts = <0 148 IRQ_TYPE_LEVEL_LOW>;
> > + clocks = <&clockgen 4 3>, <&clockgen 4 3>,
> > + <&clockgen 4 3>, <&clockgen 4 3>;
> > + clock-names = "bus", "mclk1", "mclk2", "mclk3";
> > + dma-names = "tx", "rx";
> > + dmas = <&edma0 1 47>,
> > + <&edma0 1 46>;
> > + status = "disabled";
> > + };
> > +
> > + sai2: sai at 2b60000 {
> > + #sound-dai-cells = <0>;
> > + compatible = "fsl,vf610-sai";
> > + reg = <0x0 0x2b60000 0x0 0x10000>;
> > + interrupts = <0 149 IRQ_TYPE_LEVEL_LOW>;
> > + clocks = <&clockgen 4 3>, <&clockgen 4 3>,
> > + <&clockgen 4 3>, <&clockgen 4 3>;
> > + clock-names = "bus", "mclk1", "mclk2", "mclk3";
> > + dma-names = "tx", "rx";
> > + dmas = <&edma0 1 45>,
> > + <&edma0 1 44>;
> > + status = "disabled";
> > + };
> > +
> > + edma0: edma at 2c00000 {
> > + #dma-cells = <2>;
> > + compatible = "fsl,vf610-edma";
> > + reg = <0x0 0x2c00000 0x0 0x10000>,
> > + <0x0 0x2c10000 0x0 0x10000>,
> > + <0x0 0x2c20000 0x0 0x10000>;
> > + interrupts = <0 103 IRQ_TYPE_LEVEL_LOW>,
> > + <0 103 IRQ_TYPE_LEVEL_LOW>;
> > + interrupt-names = "edma-tx", "edma-err";
> > + dma-channels = <32>;
> > + big-endian;
> > + clock-names = "dmamux0", "dmamux1";
> > + clocks = <&clockgen 4 3>,
> > + <&clockgen 4 3>;
> > + };
> > +
> > + sata: sata at 3200000 {
> > + compatible = "fsl,ls1012a-ahci";
> > + reg = <0x0 0x3200000 0x0 0x10000>;
> > + interrupts = <0 69 IRQ_TYPE_LEVEL_LOW>;
> > + clocks = <&clockgen 4 0>;
> > + };
> > + };
> > +};
> > --
> > 2.7.4
> >
> >
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] arm64: Add DTS support for FSL's LS1012A SoC
From: Harninder Rai @ 2016-11-15 6:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <DB5PR04MB16887A9480FD29B75735C707E6BF0@DB5PR04MB1688.eurprd04.prod.outlook.com>
> -----Original Message-----
> From: Harninder Rai
> Sent: Tuesday, November 15, 2016 12:15 PM
> To: 'Shawn Guo' <shawnguo@kernel.org>
> Cc: devicetree at vger.kernel.org; robh+dt at kernel.org;
> mark.rutland at arm.com; oss at buserror.net; Bhaskar U
> <bhaskar.upadhaya@nxp.com>; linux-arm-kernel at lists.infradead.org
> Subject: RE: [PATCH] arm64: Add DTS support for FSL's LS1012A SoC
>
> > > dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb
> > > dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb
> > > dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb
> >
> > It seems that the patch is not generated against mainline kernel. We
> > do not have fsl-ls1046a-qds.dtb target in mainline kernel.
> You already clarified in the following mail :)
>
> > > +
> > > + reg_1p8v: regulator at 0 {
> >
> > Drop the unit-address from node name, and name it like regulator-1p8v.
> Ok. Will take care in V2
>
> > > +
> > > +&duart0 {
> >
> > Please sort labeled nodes alphabetically.
> Ok Sure
> >
> > > + status = "okay";
> > > +};
> > > +
> > > +&sai2 {
> > > + status = "okay";
> > > +};
> >
> > <snip>
> > > + };
> > > +
> > > + timer {
> > > + compatible = "arm,armv8-timer";
> > > + /* Physical Secure PPI */
> > > + interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>,
> > > + /* Physical Non-Secure PPI */
> > > + <1 14 IRQ_TYPE_LEVEL_LOW>,
> > > + /* Virtual PPI */
> > > + <1 11 IRQ_TYPE_LEVEL_LOW>,
> > > + /* Hypervisor PPI */
> > > + <1 10 IRQ_TYPE_LEVEL_LOW>;
> >
> > The following form should be easier for read.
> >
> > interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>, /* Physical Secure
> PPI */
> > <1 14 IRQ_TYPE_LEVEL_LOW>, /* Physical Non-
> Secure PPI */
> > <1 11 IRQ_TYPE_LEVEL_LOW>, /* Virtual PPI */
> > <1 10 IRQ_TYPE_LEVEL_LOW>; /* Hypervisor PPI
> */
> >
> >
> Agreed. My bad. Will correct in v2
>
> > > + scfg: scfg at 1570000 {
> > > + compatible = "fsl,ls1012a-scfg", "syscon";
> > > + reg = <0x0 0x1570000 0x0 0x10000>;
> > > + big-endian;
> > > + };
> >
> > Please sort these nodes with unit-address in order of the address.
ok
> >
> > Shawn
^ permalink raw reply
* [PATCH v2] arm64: SMMU-v2: Workaround for Cavium ThunderX erratum 28168
From: Geetha sowjanya @ 2016-11-15 7:00 UTC (permalink / raw)
To: linux-arm-kernel
From: Tirumalesh Chalamarla <Tirumalesh.Chalamarla@cavium.com>
This patch implements Cavium ThunderX erratum 28168.
PCI requires stores complete in order. Due to erratum #28168
PCI-inbound MSI-X store to the interrupt controller are delivered
to the interrupt controller before older PCI-inbound memory stores
are committed.
Doing a sync on SMMU will make sure all prior data transfers are
completed before invoking ISR.
Signed-off-by: Tirumalesh Chalamarla <Tirumalesh.Chalamarla@cavium.com>
Signed-off-by: Geetha sowjanya <gakula@caviumnetworks.com>
---
arch/arm64/Kconfig | 11 +++++++++++
arch/arm64/Kconfig.platforms | 1 +
arch/arm64/include/asm/cpufeature.h | 3 ++-
arch/arm64/kernel/cpu_errata.c | 16 ++++++++++++++++
drivers/iommu/arm-smmu.c | 24 ++++++++++++++++++++++++
drivers/irqchip/irq-gic-common.h | 1 +
drivers/irqchip/irq-gic-v3.c | 19 +++++++++++++++++++
7 files changed, 74 insertions(+), 1 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 30398db..751972c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -474,6 +474,17 @@ config CAVIUM_ERRATUM_27456
If unsure, say Y.
+config CAVIUM_ERRATUM_28168
+ bool "Cavium erratum 28168: Make sure DMA data transfer is done before MSIX"
+ depends on ARCH_THUNDER && ARM64
+ default y
+ help
+ Due to erratum #28168 PCI-inbound MSI-X store to the interrupt
+ controller are delivered to the interrupt controller before older
+ PCI-inbound memory stores are committed. Doing a sync on SMMU
+ will make sure all prior data transfers are done before invoking ISR.
+
+ If unsure, say Y.
endmenu
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index cfbdf02..2ac4ac6 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -185,6 +185,7 @@ config ARCH_SPRD
config ARCH_THUNDER
bool "Cavium Inc. Thunder SoC Family"
+ select IRQ_PREFLOW_FASTEOI
help
This enables support for Cavium's Thunder Family of SoCs.
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 758d74f..821fc3c 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -40,8 +40,9 @@
#define ARM64_HAS_32BIT_EL0 13
#define ARM64_HYP_OFFSET_LOW 14
#define ARM64_MISMATCHED_CACHE_LINE_SIZE 15
+#define ARM64_WORKAROUND_CAVIUM_28168 16
-#define ARM64_NCAPS 16
+#define ARM64_NCAPS 17
#ifndef __ASSEMBLY__
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 0150394..0841a12 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -122,6 +122,22 @@ static void cpu_enable_trap_ctr_access(void *__unused)
MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
},
#endif
+#ifdef CONFIG_CAVIUM_ERRATUM_28168
+ {
+ /* Cavium ThunderX, T88 pass 1.x - 2.1 */
+ .desc = "Cavium erratum 28168",
+ .capability = ARM64_WORKAROUND_CAVIUM_28168,
+ MIDR_RANGE(MIDR_THUNDERX, 0x00,
+ (1 << MIDR_VARIANT_SHIFT) | 1),
+ },
+ {
+ /* Cavium ThunderX, T81 pass 1.0 */
+ .desc = "Cavium erratum 28168",
+ .capability = ARM64_WORKAROUND_CAVIUM_28168,
+ MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
+ },
+#endif
+
{
.desc = "Mismatched cache line size",
.capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index c841eb7..1b4555c 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -570,6 +570,30 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
}
}
+/*
+ * Cavium ThunderX erratum 28168
+ *
+ * Due to erratum #28168 PCI-inbound MSI-X store to the interrupt
+ * controller are delivered to the interrupt controller before older
+ * PCI-inbound memory stores are committed. Doing a sync on SMMU
+ * will make sure all prior data transfers are completed before
+ * invoking ISR.
+ *
+ */
+void cavium_arm_smmu_tlb_sync(struct device *dev)
+{
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+ struct arm_smmu_device *smmu;
+
+ smmu = fwspec_smmu(fwspec);
+ if (!smmu)
+ return;
+ __arm_smmu_tlb_sync(smmu);
+
+}
+EXPORT_SYMBOL(cavium_arm_smmu_tlb_sync);
+
+
static void arm_smmu_tlb_sync(void *cookie)
{
struct arm_smmu_domain *smmu_domain = cookie;
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
index 205e5fd..4e88f55 100644
--- a/drivers/irqchip/irq-gic-common.h
+++ b/drivers/irqchip/irq-gic-common.h
@@ -38,4 +38,5 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void gic_set_kvm_info(const struct gic_kvm_info *info);
+void cavium_arm_smmu_tlb_sync(struct device *dev);
#endif /* _IRQ_GIC_COMMON_H */
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 19d642e..723cebe 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -28,6 +28,8 @@
#include <linux/of_irq.h>
#include <linux/percpu.h>
#include <linux/slab.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic-common.h>
@@ -736,6 +738,20 @@ static inline void gic_cpu_pm_init(void) { }
#define GIC_ID_NR (1U << gic_data.rdists.id_bits)
+/*
+ * Due to #28168 erratum in ThunderX,
+ * we need to make sure DMA data transfer is done before MSIX.
+ */
+static void cavium_irq_perflow_handler(struct irq_data *data)
+{
+ struct pci_dev *pdev;
+
+ pdev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data));
+ if ((pdev->vendor != 0x177d) &&
+ ((pdev->device & 0xA000) != 0xA000))
+ cavium_arm_smmu_tlb_sync(&pdev->dev);
+}
+
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
@@ -773,6 +789,9 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
return -EPERM;
irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_fasteoi_irq, NULL, NULL);
+ if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_28168))
+ __irq_set_preflow_handler(irq,
+ cavium_irq_perflow_handler);
}
return 0;
--
1.7.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox