* [PATCH v4 2/5] ARM: dts: imx6q: Add Engicam i.CoreM6 Quad/Dual initial support
From: Fabio Estevam @ 2016-09-26 13:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOf5uw=HwErWWqvQ30ZJpb3CupqdvGZ9FnGAxh4+JVTrT6wTjw@mail.gmail.com>
On Mon, Sep 26, 2016 at 10:54 AM, Michael Trimarchi
<michael@amarulasolutions.com> wrote:
>> Why don't you simply do like this?
>>
>> reg_3p3v: regulator-3p3v {
>> compatible = "regulator-fixed";
>> regulator-name = "3P3V";
>> regulator-min-microvolt = <3300000>;
>> regulator-max-microvolt = <3300000>;
>> };
>
> Should dts rispect the schematic connection?
Yes
^ permalink raw reply
* [PATCH v4 2/5] ARM: dts: imx6q: Add Engicam i.CoreM6 Quad/Dual initial support
From: Michael Trimarchi @ 2016-09-26 13:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOMZO5BWgqxfbOepJZwqdZceSWKBnSfd38Ab2TV-LN0oDttc-Q@mail.gmail.com>
Hi
On Mon, Sep 26, 2016 at 3:47 PM, Fabio Estevam <festevam@gmail.com> wrote:
> Hi Matteo,
>
> On Mon, Sep 26, 2016 at 10:44 AM, Matteo Lisi <matteo.lisi@engicam.com> wrote:
>> Hi Fabio,
>>
>> Our SOM doesn't use external PMIC.
>>
>> We powered all devices with a fix voltage regulators that cannot be drive
>> directly from SoC so
>> any external power rail can be driven by drivers.
>
> Sure, this is fine.
>
> Why don't you simply do like this?
>
> reg_3p3v: regulator-3p3v {
> compatible = "regulator-fixed";
> regulator-name = "3P3V";
> regulator-min-microvolt = <3300000>;
> regulator-max-microvolt = <3300000>;
> };
Should dts rispect the schematic connection?
Michael
--
| Michael Nazzareno Trimarchi Amarula Solutions BV |
| COO - Founder Cruquiuskade 47 |
| +31(0)851119172 Amsterdam 1018 AM NL |
| [`as] http://www.amarulasolutions.com |
^ permalink raw reply
* [PATCH v4 2/5] ARM: dts: imx6q: Add Engicam i.CoreM6 Quad/Dual initial support
From: Fabio Estevam @ 2016-09-26 13:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <119ad2fc-8e74-1193-8ee2-417cf1e6fd49@engicam.com>
Hi Matteo,
On Mon, Sep 26, 2016 at 10:44 AM, Matteo Lisi <matteo.lisi@engicam.com> wrote:
> Hi Fabio,
>
> Our SOM doesn't use external PMIC.
>
> We powered all devices with a fix voltage regulators that cannot be drive
> directly from SoC so
> any external power rail can be driven by drivers.
Sure, this is fine.
Why don't you simply do like this?
reg_3p3v: regulator-3p3v {
compatible = "regulator-fixed";
regulator-name = "3P3V";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
^ permalink raw reply
* [PATCH v4 2/5] ARM: dts: imx6q: Add Engicam i.CoreM6 Quad/Dual initial support
From: Matteo Lisi @ 2016-09-26 13:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOMZO5CnP3=CNnQcOzra7eQ-cAwProgH+Kws0FHVOw7Q6nCDow@mail.gmail.com>
Hi Fabio,
Our SOM doesn't use external PMIC.
We powered all devices with a fix voltage regulators that cannot be
drive directly from SoC so
any external power rail can be driven by drivers.
Regards
Matteo
Il 21/09/2016 18:46, Fabio Estevam ha scritto:
> Hi Michael,
>
> On Tue, Sep 20, 2016 at 10:23 AM, Michael Trimarchi
> <michael@amarulasolutions.com> wrote:
>
>> Engicam use fixed regulator always on and on on boot. Their board does
>> not have any
>> external pmu. Is this answer to your comment?
> All I am saying is that "regulator-boot-on" and "regulator-always-on"
> properties should be removed.
>
> The "reg_3p3v" regulator will be turned on and off by the flexcan driver.
>
--
------------------------------------------------------------------------
http://www.engicam.com <http://www.engicam.com>
*/ENGICAM /*s.r.l.
50018 Scandicci - FIRENZE
Via dei Pratoni, 16
Tel. +39 055 7311387
Fax. +39 055 720608
Web www.engicam.com <http://www.engicam.com>
C.F./P.I. 05389070482
Registro Imprese di FIRENZE 542918
Capitale sociale i.v. 50.000,00?
------------------------------------------------------------------------
NOTICE: This message and attachments are intended only for the use of
their addresses and may contain confidential information belonging to
Engicam. If you are not the intended recipient, you are hereby notified
that any reading, dissemination, distribution, or copying of this
message, or any attachment, is strictly prohibited. If you have received
this message in error, please notify the original sender immediately and
delete this message, along with any attachments.
^ permalink raw reply
* [PATCH] serial: stm32: use mapbase instead of membase for DMA
From: Gerald Baeza @ 2016-09-26 13:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160923193935.3726427-1-arnd@arndb.de>
Hi Arnd
On 09/23/2016 09:38 PM, Arnd Bergmann wrote:
> Building this driver with a 64-bit dma_addr_t type results in
> a compiler warning:
>
> drivers/tty/serial/stm32-usart.c: In function 'stm32_of_dma_rx_probe':
> drivers/tty/serial/stm32-usart.c:746:20: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]
> drivers/tty/serial/stm32-usart.c: In function 'stm32_of_dma_tx_probe':
> drivers/tty/serial/stm32-usart.c:818:20: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]
>
> While the type conversion here is harmless, this hints at a different
> problem: we pass an __iomem pointer into a DMA engine, which expects
> a phys_addr_t. This happens to work because stm32 has no MMU and
> ioremap() is an identity mapping here, but it's still an incorrect
> API use. Using dma_addr_t is doubly wrong here, because that would
> be the result of dma_map_single() rather than the physical address.
>
> Using the mapbase instead fixes multiple issues:
>
> - the warning is gone
> - we don't go through ioremap in error
> - the cast is gone, making it use the correct resource_size_t/phys_addr_t
> type in the process.
>
> Fixes: 3489187204eb ("serial: stm32: adding dma support")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/tty/serial/stm32-usart.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
> index 4d3001b77e7e..2adb678a863b 100644
> --- a/drivers/tty/serial/stm32-usart.c
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -743,7 +743,7 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port,
>
> /* Configure DMA channel */
> memset(&config, 0, sizeof(config));
> - config.src_addr = (dma_addr_t)port->membase + ofs->rdr;
> + config.src_addr = port->mapbase + ofs->rdr;
> config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>
> ret = dmaengine_slave_config(stm32port->rx_ch, &config);
> @@ -815,7 +815,7 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port,
>
> /* Configure DMA channel */
> memset(&config, 0, sizeof(config));
> - config.dst_addr = (dma_addr_t)port->membase + ofs->tdr;
> + config.dst_addr = port->mapbase + ofs->tdr;
> config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>
> ret = dmaengine_slave_config(stm32port->tx_ch, &config);
>
Indeed, thanks for this finding.
Reviewed-by: Gerald Baeza <gerald.baeza@st.com>
^ permalink raw reply
* [PATCH V3 2/4] ARM64 LPC: LPC driver implementation on Hip06
From: Gabriele Paoloni @ 2016-09-26 13:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <10705430.q2aqv5uYO3@wuerfel>
Hi Arnd
> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd at arndb.de]
> Sent: 23 September 2016 14:43
> To: Gabriele Paoloni
> Cc: zhichang.yuan; linux-arm-kernel at lists.infradead.org;
> devicetree at vger.kernel.org; lorenzo.pieralisi at arm.com; minyard at acm.org;
> linux-pci at vger.kernel.org; gregkh at linuxfoundation.org; John Garry;
> will.deacon at arm.com; linux-kernel at vger.kernel.org; Yuanzhichang;
> Linuxarm; xuwei (O); linux-serial at vger.kernel.org;
> benh at kernel.crashing.org; zourongrong at gmail.com; liviu.dudau at arm.com;
> kantyzc at 163.com
> Subject: Re: [PATCH V3 2/4] ARM64 LPC: LPC driver implementation on
> Hip06
>
> On Friday, September 23, 2016 10:23:30 AM CEST Gabriele Paoloni wrote:
> > Hi Arnd
> >
> > > -----Original Message-----
> > > From: Arnd Bergmann [mailto:arnd at arndb.de]
> > > Sent: 23 September 2016 10:52
> > > To: zhichang.yuan
> > > Cc: Gabriele Paoloni; linux-arm-kernel at lists.infradead.org;
> > > devicetree at vger.kernel.org; lorenzo.pieralisi at arm.com;
> minyard at acm.org;
> > > linux-pci at vger.kernel.org; gregkh at linuxfoundation.org; John Garry;
> > > will.deacon at arm.com; linux-kernel at vger.kernel.org; Yuanzhichang;
> > > Linuxarm; xuwei (O); linux-serial at vger.kernel.org;
> > > benh at kernel.crashing.org; zourongrong at gmail.com;
> liviu.dudau at arm.com;
> > > kantyzc at 163.com
> > > Subject: Re: [PATCH V3 2/4] ARM64 LPC: LPC driver implementation on
> > > Hip06
> > >
> > > On Friday, September 23, 2016 12:27:17 AM CEST zhichang.yuan wrote:
> > > > For this patch sketch, I have a question.
> > > > Do we call pci_address_to_pio in arch_of_address_to_pio to get
> the
> > > > corresponding logical IO port
> > > > for LPC??
> > >
> > >
> > > No, of course not, that would be silly:
> > >
> > > The argument to pci_address_to_pio() is a phys_addr_t, and we we
> don't
> > > have one because there is no address associated with your PIO, that
> > > is the entire point of your driver!
> > >
> > > Also, we already know the mapping because this is what the inb/outb
> > > workaround is looking at, so there is absolutely no reason to call
> it
> > > either.
> >
> > Ok assume that we do not call pci_address_to_pio() for the ISA bus...
> > The LPC driver will register its phys address range in io_range_list,
> > then the IPMI driver probe will retrieve its physical address calling
> > of_address_to_resource and will use the indirect io to access this
> > address.
> >
> > From the perspective of the indirect IO function the input parameter
> > is an unsigned long addr that (now) can be either:
> > 1) an IO token coming from a legacy pci device
> > 2) a phys address that lives on the LPC bus
> >
> > These are conceptually two separate address spaces (and actually they
> > both start from 0).
>
> Why? Any IORESOURCE_IO address always refers to the logical I/O port
> range in Linux, not the physical address that is used on a bus.
>
> > If the input parameter can live on different address spaces that are
> > overlapped, even if I save the used LPC range in arm64_extio_ops-
> >start/end
> > there is no way for the indirect IO to tell if the input parameter is
> > an I/O token or a phys address that belongs to LPC...
>
Assume that in the probe function the LPC drivers calls pci_register_io_range
for the LPC cpu address range (0 to PCIBIOS_MIN_I0) and does not scan
the children DT nodes.
Consider for example the ipmi driver:
When the reg property is read to retrieve the ipmi <<i/o port>> in
http://lxr.free-electrons.com/source/drivers/char/ipmi/ipmi_si_intf.c#L2622
if we do not call pci_address_to_pio in __of_address_to_resource the input
parameter of inb/outb will be the cpu address of the ipmi (not translated
to a unique token id).
So inb/outb at this stage can be called passing either a cpu address or a
token io port.
If we set arm64_extio_ops->start/end to 0 and PCIBIOS_MIN_I0 respectively
we still cannot tell inside inb/outb if the passed address is a token or
an LPC cpu address as the ipmi cpu address can overlap with another device
I/O token...
My suggestion is to call pci_address_to_pio even for devices living on
the LPC bus; then in the LPC probe we set arm64_extio_ops->start/end to
the I/O tokens that correspond to the LPC cpu address range (in the LPC probe
function we call pci_address_to_pio after we have called pci_register_io_range);
finally in inb/outb we know that we can get only an I/O token as input
parameter and we check it against arm64_extio_ops->start/end to decide
whether to call the LPC accessors or readb/writeb...
> The start address is the offset: if you get an address between 'start'
> and 'end', you subtract the 'start' from it, and use that to call
> the registered driver function. That works because we can safely
> assume that the bus address range that the LPC driver registers starts
> zero.
Sorry I cannot follow what you said here above: <<if you get an address
between 'start' and 'end'>>...in which function?
Thanks
Gab
>
> Arnd
^ permalink raw reply
* [PATCH 5/5] arm64: Add uprobe support
From: Pratyush Anand @ 2016-09-26 13:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160926110159.GB27498@e104818-lin.cambridge.arm.com>
On 26/09/2016:12:01:59 PM, Catalin Marinas wrote:
> On Sun, Sep 25, 2016 at 10:32:28PM +0530, Pratyush Anand wrote:
> > On Fri, Sep 23, 2016 at 6:35 PM, Catalin Marinas
> > <catalin.marinas@arm.com> wrote:
> > > On Fri, Sep 23, 2016 at 09:42:30AM +0530, Pratyush Anand wrote:
> > >> On 22/09/2016:05:50:30 PM, Catalin Marinas wrote:
> > >> > On Thu, Sep 22, 2016 at 08:53:28AM +0530, Pratyush Anand wrote:
> > >> > > On 21/09/2016:06:04:04 PM, Catalin Marinas wrote:
> >
> > >> > As a quick workaround you could check mm->task_size > TASK_SIZE_32 in
> > >> > the arch_uprobe_analyze_insn() function.
> > >>
> > >> It would be doable. TASK_SIZE_32 is defined only for COMPAT. So, may be I can
> > >> return -EINVAL when mm->task_size < TASK_SIZE_64.
> > >
> > > That's just a temporary workaround. If we ever merge ILP32, this test
> > > would no longer be enough (as the ISA is AArch64 but with TASK_SIZE_32).
> >
> > OK.. So what about doing something similar what x86 is doing.
> > We can have a flag for task Type in arch specific mm_context_t. We
> > also set this flag in COMPAT_SET_PERSONALITY() along with setting
> > thread_info flag, and we clear them in SET_PERSONALITY().
>
> This looks like a better approach.
>
> > > Looking at prepare_uprobe(), we have a weak is_trap_insn() function.
> > > This check is meaningless without knowing which instruction set we
> > > target. A false positive here, however, is not that bad as we wouldn't
> > > end up inserting the wrong breakpoint in the executable. But it looks to
> > > me like the core uprobe code needs to pass some additional information
> > > like the type of task or ELF format to the arch code to make a useful
> > > choice of breakpoint type.
> >
> > It seems that 'strtle r0, [r0], #160' would have the closest matching
> > aarch32 instruction wrt BRK64_OPCODE_UPROBES(0xd42000A0). But that too
> > seems a bad instruction. So, may be we can use still weak
> > is_trap_insn().
>
> Even if the is_trap_insn() check passes, we would reject the probe in
> arch_uprobe_analyze_insn() immediately after based on the mm type check,
> so not too bad.
OK..I will have an always returning false from arm64 is_trap_insn() in v2.
>
> If we add support for probing 32-bit tasks, I would rather have
> is_trap_insn() take the mm_struct as argument so that a non-weak
> implementation can check for the correct encoding.
Yes, for 32 bit task we would need mm_struct as arg in is_trap_insn() as well as
in is_swbp_insn(). We would also need to have arm64 specific set_swbp().
Thanks for all your input. It was helpful. I will send V2 soon.
~Pratyush
^ permalink raw reply
* [RFC PATCH 1/2] watchdog: imx2: fix hang-up on boot for i.MX21, i.MX27 and i.MX31 SoCs
From: Guenter Roeck @ 2016-09-26 13:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474850361-20884-2-git-send-email-vz@mleia.com>
On 09/25/2016 05:39 PM, Vladimir Zapolskiy wrote:
> Power down counter enable/disable bit switch is located in WMCR
> register, but watchdog controllers found on legacy i.MX21, i.MX27 and
> i.MX31 SoCs don't have this register. As a result of writing data to
> the non-existing register on driver probe the SoC hangs up, to fix the
> problem add more OF compatible strings and on this basis get
> information about availability of the WMCR register.
>
> Fixes: 5fe65ce7ccbb ("watchdog: imx2_wdt: Disable power down counter on boot")
> Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
> ---
> drivers/watchdog/imx2_wdt.c | 47 +++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 45 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
> index 62f346b..b6763e0 100644
> --- a/drivers/watchdog/imx2_wdt.c
> +++ b/drivers/watchdog/imx2_wdt.c
> @@ -29,6 +29,7 @@
> #include <linux/module.h>
> #include <linux/moduleparam.h>
> #include <linux/of_address.h>
> +#include <linux/of_device.h>
> #include <linux/platform_device.h>
> #include <linux/regmap.h>
> #include <linux/watchdog.h>
> @@ -57,6 +58,10 @@
>
> #define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
>
> +struct imx2_wdt_data {
> + bool has_pdc;
> +};
> +
> struct imx2_wdt_device {
> struct clk *clk;
> struct regmap *regmap;
> @@ -64,6 +69,8 @@ struct imx2_wdt_device {
> bool ext_reset;
> };
>
> +static const struct of_device_id imx2_wdt_dt_ids[];
> +
> static bool nowayout = WATCHDOG_NOWAYOUT;
> module_param(nowayout, bool, 0);
> MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
> @@ -200,10 +207,13 @@ static const struct regmap_config imx2_wdt_regmap_config = {
>
> static int __init imx2_wdt_probe(struct platform_device *pdev)
> {
> + const struct of_device_id *of_id;
> + const struct imx2_wdt_data *data;
> struct imx2_wdt_device *wdev;
> struct watchdog_device *wdog;
> struct resource *res;
> void __iomem *base;
> + bool has_pdc;
> int ret;
> u32 val;
>
> @@ -261,12 +271,24 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
> set_bit(WDOG_HW_RUNNING, &wdog->status);
> }
>
> + if (pdev->dev.of_node) {
> + of_id = of_match_device(imx2_wdt_dt_ids, &pdev->dev);
> + if (!of_id)
> + return -ENODEV;
> +
> + data = of_id->data;
> + has_pdc = data->has_pdc;
> + } else {
> + has_pdc = false;
> + }
> +
> /*
> * Disable the watchdog power down counter at boot. Otherwise the power
> * down counter will pull down the #WDOG interrupt line for one clock
> * cycle.
> */
> - regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
> + if (has_pdc)
> + regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
>
> ret = watchdog_register_device(wdog);
> if (ret) {
> @@ -363,8 +385,29 @@ static int imx2_wdt_resume(struct device *dev)
> static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
> imx2_wdt_resume);
>
> +static const struct imx2_wdt_data imx21_wdt_data = {
> + .has_pdc = false,
> +};
> +
> +static const struct imx2_wdt_data imx25_wdt_data = {
> + .has_pdc = true,
> +};
> +
> static const struct of_device_id imx2_wdt_dt_ids[] = {
> - { .compatible = "fsl,imx21-wdt", },
> + { .compatible = "fsl,imx21-wdt", .data = &imx21_wdt_data },
Please just specify the flag directly, as in
.data = (void *) true
or, if you prefer, use defines.
.data = (void *) IMX_SUPPORTS_PDC
Then, in above code:
has_pdc = (bool) of_id->data;
Guenter
> + { .compatible = "fsl,imx25-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,imx27-wdt", .data = &imx21_wdt_data },
> + { .compatible = "fsl,imx31-wdt", .data = &imx21_wdt_data },
> + { .compatible = "fsl,imx35-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,imx50-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,imx51-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,imx53-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,imx6q-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,imx6sl-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,imx6sx-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,imx6ul-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,imx7d-wdt", .data = &imx25_wdt_data },
> + { .compatible = "fsl,vf610-wdt", .data = &imx25_wdt_data },
> { /* sentinel */ }
> };
> MODULE_DEVICE_TABLE(of, imx2_wdt_dt_ids);
>
^ permalink raw reply
* [PATCH V5 3/4] drm/bridge: Add driver for GE B850v3 LVDS/DP++ Bridge
From: Archit Taneja @ 2016-09-26 12:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5734-57e90c80-11-398829c0@7164733>
On 09/26/2016 05:24 PM, Peter Senna Tschudin wrote:
>
> On Monday, September 26, 2016 12:29 CEST, Archit Taneja <architt@codeaurora.org> wrote:
>
>> Hi,
>>
>> Some comments.
>
> Thank you for the review!
>
>>
>> On 08/09/2016 10:11 PM, Peter Senna Tschudin wrote:
>>> Add a driver that create a drm_bridge and a drm_connector for the LVDS
>>> to DP++ display bridge of the GE B850v3.
>>>
>>> There are two physical bridges on the video signal pipeline: a
>>> STDP4028(LVDS to DP) and a STDP2690(DP to DP++). The hardware and
>>> firmware made it complicated for this binding to comprise two device
>>> tree nodes, as the design goal is to configure both bridges based on
>>> the LVDS signal, which leave the driver powerless to control the video
>>> processing pipeline. The two bridges behaves as a single bridge, and
>>> the driver is only needed for telling the host about EDID / HPD, and
>>> for giving the host powers to ack interrupts. The video signal pipeline
>>> is as follows:
>>>
>>> Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
>>>
>>> Cc: Martyn Welch <martyn.welch@collabora.co.uk>
>>> Cc: Martin Donnelly <martin.donnelly@ge.com>
>>> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
>>> Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>> Cc: Philipp Zabel <p.zabel@pengutronix.de>
>>> Cc: Rob Herring <robh@kernel.org>
>>> Cc: Fabio Estevam <fabio.estevam@nxp.com>
>>> CC: David Airlie <airlied@linux.ie>
>>> CC: Thierry Reding <treding@nvidia.com>
>>> CC: Thierry Reding <thierry.reding@gmail.com>
>>> Reviewed-by: Enric Balletbo <enric.balletbo@collabora.com>
>>> Signed-off-by: Peter Senna Tschudin <peter.senna@collabora.com>
>>> ---
>>> Changes from V4:
>>> - Check the output of the first call to i2c_smbus_write_word_data() and return
>>> it's error code for failing gracefully on i2c issues
>>> - Renamed the i2c_driver.name from "ge,b850v3-lvds-dp" to "b850v3-lvds-dp" to
>>> remove the comma from the driver name
>>>
>>> Changes from V3:
>>> - 3/4 instead of 4/5
>>> - Tested on next-20160804
>>>
>>> Changes from V2:
>>> - Made it atomic to be applied on next-20160729 on top of Liu Ying changes
>>> that made imx-ldb atomic
>>>
>>> Changes from V1:
>>> - New commit message
>>> - Removed 3 empty entry points
>>> - Removed memory leak from ge_b850v3_lvds_dp_get_modes()
>>> - Added a lock for mode setting
>>> - Removed a few blank lines
>>> - Changed the order at Makefile and Kconfig
>>>
>>> MAINTAINERS | 8 +
>>> drivers/gpu/drm/bridge/Kconfig | 11 +
>>> drivers/gpu/drm/bridge/Makefile | 1 +
>>> drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c | 405 +++++++++++++++++++++++++++++
>>> 4 files changed, 425 insertions(+)
>>> create mode 100644 drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index a306795..e8d106a 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -5142,6 +5142,14 @@ W: https://linuxtv.org
>>> S: Maintained
>>> F: drivers/media/radio/radio-gemtek*
>>>
>>> +GENERAL ELECTRIC B850V3 LVDS/DP++ BRIDGE
>>> +M: Peter Senna Tschudin <peter.senna@collabora.com>
>>> +M: Martin Donnelly <martin.donnelly@ge.com>
>>> +M: Martyn Welch <martyn.welch@collabora.co.uk>
>>> +S: Maintained
>>> +F: drivers/gpu/drm/bridge/ge_b850v3_dp2.c
>>> +F: Documentation/devicetree/bindings/ge/b850v3_dp2_bridge.txt
>>> +
>>> GENERIC GPIO I2C DRIVER
>>> M: Haavard Skinnemoen <hskinnemoen@gmail.com>
>>> S: Supported
>>
>> Could you move the MAINTAINERS change to a different patch? It would
>> make it easier to integrate separately.
>
> If needed, yes sure.
>
>>
>>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
>>> index b590e67..b4b70fb 100644
>>> --- a/drivers/gpu/drm/bridge/Kconfig
>>> +++ b/drivers/gpu/drm/bridge/Kconfig
>>> @@ -32,6 +32,17 @@ config DRM_DW_HDMI_AHB_AUDIO
>>> Designware HDMI block. This is used in conjunction with
>>> the i.MX6 HDMI driver.
>>>
>>> +config DRM_GE_B850V3_LVDS_DP
>>> + tristate "GE B850v3 LVDS to DP++ display bridge"
>>> + depends on OF
>>> + select DRM_KMS_HELPER
>>> + select DRM_PANEL
>>> + ---help---
>>> + This is a driver for the display bridge of
>>> + GE B850v3 that convert dual channel LVDS
>>> + to DP++. This is used with the i.MX6 imx-ldb
>>> + driver.
>>> +
>>> config DRM_NXP_PTN3460
>>> tristate "NXP PTN3460 DP/LVDS bridge"
>>> depends on OF
>>> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
>>> index efdb07e..b9606f3 100644
>>> --- a/drivers/gpu/drm/bridge/Makefile
>>> +++ b/drivers/gpu/drm/bridge/Makefile
>>> @@ -3,6 +3,7 @@ ccflags-y := -Iinclude/drm
>>> obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
>>> obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
>>> obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
>>> +obj-$(CONFIG_DRM_GE_B850V3_LVDS_DP) += ge_b850v3_lvds_dp.o
>>> obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
>>> obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
>>> obj-$(CONFIG_DRM_SII902X) += sii902x.o
>>> diff --git a/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
>>> new file mode 100644
>>> index 0000000..81e9279
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
>>> @@ -0,0 +1,405 @@
>>> +/*
>>> + * Driver for GE B850v3 DP display bridge
>>> +
>>> + * Copyright (c) 2016, Collabora Ltd.
>>> + * Copyright (c) 2016, General Electric Company
>>> +
>>> + * This program is free software; you can redistribute it and/or modify it
>>> + * under the terms and conditions of the GNU General Public License,
>>> + * version 2, as published by the Free Software Foundation.
>>> +
>>> + * This program is distributed in the hope 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.
>>> +
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>>> +
>>> + * This driver creates a drm_bridge and a drm_connector for the LVDS to DP++
>>> + * display bridge of the GE B850v3. There are two physical bridges on the video
>>> + * signal pipeline: a STDP4028(LVDS to DP) and a STDP2690(DP to DP++). However
>>> + * the physical bridges are automatically configured by the input video signal,
>>> + * and the driver has no access to the video processing pipeline. The driver is
>>> + * only needed to read EDID from the STDP2690 and to handle HPD events from the
>>> + * STDP4028. The driver communicates with both bridges over i2c. The video
>>> + * signal pipeline is as follows:
>>> + *
>>> + * Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
>>> + *
>>> + */
>>> +
>>> +#include <linux/gpio.h>
>>> +#include <linux/i2c.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <drm/drm_atomic.h>
>>> +#include <drm/drm_atomic_helper.h>
>>> +#include <drm/drm_crtc_helper.h>
>>> +#include <drm/drm_edid.h>
>>> +#include <drm/drmP.h>
>>> +
>>> +/*
>>> + * 220Mhz is a limitation of the host, as the bridge is capable of up to
>>> + * 330Mhz. See section 9.2.1.2.4 of the i.MX 6Dual/6Quad Applications
>>> + * Processor Reference Manual for more information about the 220Mhz limit.
>>> + * The imx-ldb driver will warn about clocks over 170Mhz, but it seem to work
>>> + * fine.
>>> + */
>>> +#define MAX_PIXEL_CLOCK 220000
>>> +
>>> +#define EDID_EXT_BLOCK_CNT 0x7E
>>> +
>>> +#define STDP4028_IRQ_OUT_CONF_REG 0x02
>>> +#define STDP4028_DPTX_IRQ_EN_REG 0x3C
>>> +#define STDP4028_DPTX_IRQ_STS_REG 0x3D
>>> +#define STDP4028_DPTX_STS_REG 0x3E
>>> +
>>> +#define STDP4028_DPTX_DP_IRQ_EN 0x1000
>>> +
>>> +#define STDP4028_DPTX_HOTPLUG_IRQ_EN 0x0400
>>> +#define STDP4028_DPTX_LINK_CH_IRQ_EN 0x2000
>>> +#define STDP4028_DPTX_IRQ_CONFIG \
>>> + (STDP4028_DPTX_LINK_CH_IRQ_EN | STDP4028_DPTX_HOTPLUG_IRQ_EN)
>>> +
>>> +#define STDP4028_DPTX_HOTPLUG_STS 0x0200
>>> +#define STDP4028_DPTX_LINK_STS 0x1000
>>> +#define STDP4028_CON_STATE_CONNECTED \
>>> + (STDP4028_DPTX_HOTPLUG_STS | STDP4028_DPTX_LINK_STS)
>>> +
>>> +#define STDP4028_DPTX_HOTPLUG_CH_STS 0x0400
>>> +#define STDP4028_DPTX_LINK_CH_STS 0x2000
>>> +#define STDP4028_DPTX_IRQ_CLEAR \
>>> + (STDP4028_DPTX_LINK_CH_STS | STDP4028_DPTX_HOTPLUG_CH_STS)
>>> +
>>> +struct ge_b850v3_lvds_dp {
>>> + struct drm_connector connector;
>>> + struct drm_bridge bridge;
>>> + struct i2c_client *ge_b850v3_lvds_dp_i2c;
>>> + struct i2c_client *edid_i2c;
>>> + struct edid *edid;
>>> + struct mutex lock;
>>> +};
>>> +
>>> +static inline struct ge_b850v3_lvds_dp *
>>> + bridge_to_ge_b850v3_lvds_dp(struct drm_bridge *bridge)
>>> +{
>>> + return container_of(bridge, struct ge_b850v3_lvds_dp, bridge);
>>> +}
>>> +
>>> +static inline struct ge_b850v3_lvds_dp *
>>> + connector_to_ge_b850v3_lvds_dp(struct drm_connector *connector)
>>> +{
>>> + return container_of(connector, struct ge_b850v3_lvds_dp, connector);
>>> +}
>>> +
>>> +u8 *stdp2690_get_edid(struct i2c_client *client)
>>> +{
>>> + struct i2c_adapter *adapter = client->adapter;
>>> + unsigned char start = 0x00;
>>> + unsigned int total_size;
>>> + u8 *block = kmalloc(EDID_LENGTH, GFP_KERNEL);
>>> +
>>> + struct i2c_msg msgs[] = {
>>> + {
>>> + .addr = client->addr,
>>> + .flags = 0,
>>> + .len = 1,
>>> + .buf = &start,
>>> + }, {
>>> + .addr = client->addr,
>>> + .flags = I2C_M_RD,
>>> + .len = EDID_LENGTH,
>>> + .buf = block,
>>> + }
>>> + };
>>> +
>>> + if (!block)
>>> + return NULL;
>>> +
>>> + if (i2c_transfer(adapter, msgs, 2) != 2) {
>>> + DRM_ERROR("Unable to read EDID.\n");
>>> + goto err;
>>> + }
>>> +
>>> + if (!drm_edid_block_valid(block, 0, false, NULL)) {
>>> + DRM_ERROR("Invalid EDID block\n");
>>> + goto err;
>>> + }
>>> +
>>> + total_size = (block[EDID_EXT_BLOCK_CNT] + 1) * EDID_LENGTH;
>>> + if (total_size > EDID_LENGTH) {
>>> + kfree(block);
>>> + block = kmalloc(total_size, GFP_KERNEL);
>>> + if (!block)
>>> + return NULL;
>>> +
>>> + /* Yes, read the entire buffer, and do not skip the first
>>> + * EDID_LENGTH bytes.
>>> + */
>>> + start = 0x00;
>>> + msgs[1].len = total_size;
>>> + msgs[1].buf = block;
>>> +
>>> + if (i2c_transfer(adapter, msgs, 2) != 2) {
>>> + DRM_ERROR("Unable to read EDID extension blocks.\n");
>>> + goto err;
>>> + }
>>> + }
>>> +
>>> + return block;
>>> +
>>> +err:
>>> + kfree(block);
>>> + return NULL;
>>> +}
>>> +
>>> +static int ge_b850v3_lvds_dp_get_modes(struct drm_connector *connector)
>>> +{
>>> + struct ge_b850v3_lvds_dp *ptn_bridge;
>>> + struct i2c_client *client;
>>> + int num_modes = 0;
>>> +
>>> + ptn_bridge = connector_to_ge_b850v3_lvds_dp(connector);
>>> + client = ptn_bridge->edid_i2c;
>>> +
>>> + mutex_lock(&ptn_bridge->lock);
>>> +
>>> + kfree(ptn_bridge->edid);
>>> + ptn_bridge->edid = (struct edid *) stdp2690_get_edid(client);
>>> +
>>> + if (ptn_bridge->edid) {
>>> + drm_mode_connector_update_edid_property(connector,
>>> + ptn_bridge->edid);
>>> + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
>>> + }
>>> +
>>> + mutex_unlock(&ptn_bridge->lock);
>>> +
>>> + return num_modes;
>>> +}
>>> +
>>> +
>>> +static enum drm_mode_status ge_b850v3_lvds_dp_mode_valid(
>>> + struct drm_connector *connector, struct drm_display_mode *mode)
>>> +{
>>> + if (mode->clock > MAX_PIXEL_CLOCK) {
>>> + DRM_INFO("The pixel clock for the mode %s is too high, and not supported.",
>>> + mode->name);
>>> + return MODE_CLOCK_HIGH;
>>> + }
>>> +
>>> + return MODE_OK;
>>> +}
>>> +
>>> +static const struct
>>> +drm_connector_helper_funcs ge_b850v3_lvds_dp_connector_helper_funcs = {
>>> + .get_modes = ge_b850v3_lvds_dp_get_modes,
>>> + .mode_valid = ge_b850v3_lvds_dp_mode_valid,
>>> +};
>>> +
>>> +static enum drm_connector_status ge_b850v3_lvds_dp_detect(
>>> + struct drm_connector *connector, bool force)
>>> +{
>>> + struct ge_b850v3_lvds_dp *ptn_bridge =
>>> + connector_to_ge_b850v3_lvds_dp(connector);
>>> + struct i2c_client *ge_b850v3_lvds_dp_i2c =
>>> + ptn_bridge->ge_b850v3_lvds_dp_i2c;
>>> + s32 link_state;
>>> +
>>> + link_state = i2c_smbus_read_word_data(ge_b850v3_lvds_dp_i2c,
>>> + STDP4028_DPTX_STS_REG);
>>> +
>>> + if (link_state == STDP4028_CON_STATE_CONNECTED)
>>> + return connector_status_connected;
>>> +
>>> + if (link_state == 0)
>>> + return connector_status_disconnected;
>>> +
>>> + return connector_status_unknown;
>>> +}
>>> +
>>> +static const struct drm_connector_funcs ge_b850v3_lvds_dp_connector_funcs = {
>>> + .dpms = drm_atomic_helper_connector_dpms,
>>> + .fill_modes = drm_helper_probe_single_connector_modes,
>>> + .detect = ge_b850v3_lvds_dp_detect,
>>> + .destroy = drm_connector_cleanup,
>>> + .reset = drm_atomic_helper_connector_reset,
>>> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>>> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>>> +};
>>> +
>>> +static irqreturn_t ge_b850v3_lvds_dp_irq_handler(int irq, void *dev_id)
>>> +{
>>> + struct ge_b850v3_lvds_dp *ptn_bridge = dev_id;
>>> + struct i2c_client *ge_b850v3_lvds_dp_i2c
>>> + = ptn_bridge->ge_b850v3_lvds_dp_i2c;
>>> +
>>> + mutex_lock(&ptn_bridge->lock);
>>> +
>>> + i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
>>> + STDP4028_DPTX_IRQ_STS_REG, STDP4028_DPTX_IRQ_CLEAR);
>>> +
>>> + mutex_unlock(&ptn_bridge->lock);
>>> +
>>> + if (ptn_bridge->connector.dev)
>>> + drm_kms_helper_hotplug_event(ptn_bridge->connector.dev);
>>> +
>>> + return IRQ_HANDLED;
>>> +}
>>> +
>>> +static int ge_b850v3_lvds_dp_attach(struct drm_bridge *bridge)
>>> +{
>>> + struct ge_b850v3_lvds_dp *ptn_bridge
>>> + = bridge_to_ge_b850v3_lvds_dp(bridge);
>>> + struct drm_connector *connector = &ptn_bridge->connector;
>>> + struct i2c_client *ge_b850v3_lvds_dp_i2c
>>> + = ptn_bridge->ge_b850v3_lvds_dp_i2c;
>>> + int ret;
>>> +
>>> + if (!bridge->encoder) {
>>> + DRM_ERROR("Parent encoder object not found");
>>> + return -ENODEV;
>>> + }
>>> +
>>> + connector->polled = DRM_CONNECTOR_POLL_HPD;
>>> +
>>> + drm_connector_helper_add(connector,
>>> + &ge_b850v3_lvds_dp_connector_helper_funcs);
>>> +
>>> + ret = drm_connector_init(bridge->dev, connector,
>>> + &ge_b850v3_lvds_dp_connector_funcs,
>>> + DRM_MODE_CONNECTOR_DisplayPort);
>>> + if (ret) {
>>> + DRM_ERROR("Failed to initialize connector with drm\n");
>>> + return ret;
>>> + }
>>> +
>>> + drm_connector_register(connector);
>>
>> Connectors shouldn't be registered in the bridge driver, they should
>> be registered by the kms driver after drm_dev_register is called.
>> The drm_connector_register_all() API is used for that.
>
> Hmm, I got this from:
>
> drivers/gpu/drm/bridge/nxp-ptn3460.c: drm_connector_register(&ptn_bridge->connector);
> drivers/gpu/drm/bridge/parade-ps8622.c: drm_connector_register(&ps8622->connector);
> drivers/gpu/drm/bridge/analogix-anx78xx.c: err = drm_connector_register(&anx78xx->connector);
Yeah, we need to get rid of these too, eventually.
The connectors should be registered only after the
drm device has been registered. Relying on the drm
core to do that ensures that. See drm_modeset_register_all()
for more info.
Also, btw, the imx driver shouldn't use the load() drm_driver ops
anymore. You would want to change that too. See the comments in
drm_dev_register() in drm_drv.c for more details.
>
>
>>
>>> + ret = drm_mode_connector_attach_encoder(connector, bridge->encoder);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + drm_bridge_enable(bridge);
>>
>> This drm_bridge_enable() doesn't seem to serve any purpose here. It also
>> doesn't seem to make much sense to call drm_bridge_() funcs within a
>> bridge op itself.
>
> Yes, removing this line has no effect. I'll send V6. Thank you!
>
>>
>>> + if (ge_b850v3_lvds_dp_i2c->irq) {
>>> + drm_helper_hpd_irq_event(connector->dev);
>>> +
>>> + ret = devm_request_threaded_irq(&ge_b850v3_lvds_dp_i2c->dev,
>>> + ge_b850v3_lvds_dp_i2c->irq, NULL,
>>> + ge_b850v3_lvds_dp_irq_handler,
>>> + IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
>>> + "ge-b850v3-lvds-dp", ptn_bridge);
>>
>> Is there a reason why we register the interrupt handler here and not in
>> probe?
>
> Yes, drm_bridge_funcs.attach() is called when drm decides it is time to initialize the bridge, which means the drm is already running. i2c_driver.probe() is likely to be called way before drm initializes, and if for some reason the bridge is not attached, there is no need for the interrupt handler. In this case the interrupt handler is mostly used for events related to display plugging/unplugging.
The i2c device can probe before drm, this should be fixed by making sure
the device's interrupts are masked before we request the handler, and
unmasking it when we know it is ready for use.
If a bridge device exists and isn't attached, then we should question
why it probed in the first place if it wasn't to be used.
Besides, in the current scenario, consider the case where the imx
driver's call to drm_bridge_attach() succeeds, but then later fails at
some point. There would be no one to remove this interrupt handler. The
devm_ api attaches the lifetime of the handler with the i2c device, not
the drm device.
Also, the call to drm_helper_hpd_irq_event(drm_dev) should go too. These
should be called only when the drm device is registered.
Thanks,
Archit
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH v4] devicetree: bindings: uart: Add new compatible string for ZynqMP
From: Nava kishore Manne @ 2016-09-26 12:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160923223747.GA1163@rob-hp-laptop>
> -----Original Message-----
> From: Rob Herring [mailto:robh at kernel.org]
> Sent: Saturday, September 24, 2016 4:08 AM
> To: Nava kishore Manne <navam@xilinx.com>
> Cc: gregkh at linuxfoundation.org; mark.rutland at arm.com; jslaby at suse.com;
> michal.simek at xilinx.com; Soren Brinkmann <sorenb@xilinx.com>; linux-
> serial at vger.kernel.org; devicetree at vger.kernel.org; linux-
> kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org; Punnaiah
> Choudary Kalluri <punnaia@xilinx.com>; Nava kishore Manne
> <navam@xilinx.com>
> Subject: Re: [PATCH v4] devicetree: bindings: uart: Add new compatible
> string for ZynqMP
>
> On Fri, Sep 23, 2016 at 04:55:48PM +0530, Nava kishore Manne wrote:
> > From: Nava kishore Manne <nava.manne@xilinx.com>
> >
> > This patch Adds the new compatible string for ZynqMP.
> >
> > Signed-off-by: Nava kishore Manne <navam@xilinx.com>
> > ---
> > Changes for v4:
> > -Modified the ChangeLog comment.
> > Changes for v3:
> > -Added changeLog comment.
> > Changes for v2:
> > -None
> >
> > Documentation/devicetree/bindings/serial/cdns,uart.txt | 3 ++-
> > 1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/devicetree/bindings/serial/cdns,uart.txt
> b/Documentation/devicetree/bindings/serial/cdns,uart.txt
> > index a3eb154..4fe7aae 100644
> > --- a/Documentation/devicetree/bindings/serial/cdns,uart.txt
> > +++ b/Documentation/devicetree/bindings/serial/cdns,uart.txt
> > @@ -1,7 +1,8 @@
> > Binding for Cadence UART Controller
> >
> > Required properties:
> > -- compatible : should be "cdns,uart-r1p8", or "xlnx,xuartps"
> > +- compatible : should be "cdns,uart-r1p8", or "xlnx,xuartps" for Zynq and
> > + "cdns,uart-r1p12" for Zynq Ultrascale+ MPSoC uart controller.
>
> Please format this as one valid combination per line.
>
> xuartps is not very specific. It needs some abbreviation of "Zynq
> Ultrascale+ MPSoC" in it.
>
Will fix the above comments in the next version.
Regards,
Navakishore.
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
^ permalink raw reply
* [PATCH 2/2] drivers: cci: add missing CCI port availability firmware check
From: Jon Medhurst (Tixy) @ 2016-09-26 12:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160923130907.4187-2-lorenzo.pieralisi@arm.com>
On Fri, 2016-09-23 at 14:09 +0100, Lorenzo Pieralisi wrote:
> The CCI ports programming interface is available to the kernel
> only when booted in secure mode (or when firmware enables
> non-secure access to override CCI ports control). In both cases,
> firmware reports the CCI ports availability through the device
> tree CCI ports nodes, which must be parsed and their status checked
> by the kernel probing path.
>
> This check is currently missing and may cause the kernel to
> erroneously believe it is free to take control of CCI ports
> where in practice CCI ports control is forbidden.
>
> Add the missing CCI port availability check to the CCI driver
> in order to guarantee sane CCI usage.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Liviu Dudau <liviu.dudau@arm.com>
> Cc: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
> Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> ---
Tested-by: Jon Medhurst <tixy@linaro.org>
> drivers/bus/arm-cci.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
> index 5755907f..3c7a1c7 100644
> --- a/drivers/bus/arm-cci.c
> +++ b/drivers/bus/arm-cci.c
> @@ -2199,6 +2199,9 @@ static int cci_probe_ports(struct device_node *np)
> if (!of_match_node(arm_cci_ctrl_if_matches, cp))
> continue;
>
> + if (!of_device_is_available(cp))
> + continue;
> +
> i = nb_ace + nb_ace_lite;
>
> if (i >= nb_cci_ports)
> @@ -2241,6 +2244,13 @@ static int cci_probe_ports(struct device_node *np)
> ports[i].dn = cp;
> }
>
> + /*
> + * If there is no CCI port that is under kernel control
> + * return early and report probe status.
> + */
> + if (!nb_ace && !nb_ace_lite)
> + return -ENODEV;
> +
> /* initialize a stashed array of ACE ports to speed-up look-up */
> cci_ace_init_ports();
>
^ permalink raw reply
* [PATCH 1/2] ARM: vexpress: refine MCPM smp operations override criteria
From: Jon Medhurst (Tixy) @ 2016-09-26 12:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160923130907.4187-1-lorenzo.pieralisi@arm.com>
On Fri, 2016-09-23 at 14:09 +0100, Lorenzo Pieralisi wrote:
> Current vexpress smp init code detects whether to override the
> default smp ops with MCPM smp ops by matching the "cci-400"
> compatible string, in that MCPM requires control over CCI ports
> to manage low-power states entry/exit.
>
> The "cci-400" compatible string check is a necessary but not
> sufficient condition for MCPM to work, because the cci-400
> can be made visible to the kernel, but firmware can nonetheless
> disable non-secure CCI ports control, while still allowing PMU
> access; if booted in non-secure world, the kernel would still
> blindly override smp operations with MCPM operations, resulting
> in kernel faults when the CCI ports programming interface is
> accessed from non-secure world.
>
> This means that the "cci-400" compatible string check would
> result in a false positive in systems that eg boot in HYP mode,
> where CCI ports non-secure access is explicitly not allowed,
> and it is reported in the respective device tree nodes with
> CCI ports marked as disabled.
>
> Refactor the smp operations initialization to make sure that
> the kernel is actually allowed to take control over CCI ports
> (by enabling MCPM smp operations) before overriding default
> vexpress smp operations.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Liviu Dudau <liviu.dudau@arm.com>
> Cc: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> ---
Tested-by: Jon Medhurst <tixy@linaro.org>
> arch/arm/mach-vexpress/platsmp.c | 31 ++++++++++++++++++++++++-------
> 1 file changed, 24 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
> index 8b8d072..6cfd782 100644
> --- a/arch/arm/mach-vexpress/platsmp.c
> +++ b/arch/arm/mach-vexpress/platsmp.c
> @@ -26,17 +26,34 @@
> bool __init vexpress_smp_init_ops(void)
> {
> #ifdef CONFIG_MCPM
> + int cpu;
> + struct device_node *cpu_node, *cci_node;
> +
> /*
> - * The best way to detect a multi-cluster configuration at the moment
> - * is to look for the presence of a CCI in the system.
> + * The best way to detect a multi-cluster configuration
> + * is to detect if the kernel can take over CCI ports
> + * control. Loop over possible CPUs and check if CCI
> + * port control is available.
> * Override the default vexpress_smp_ops if so.
> */
> - struct device_node *node;
> - node = of_find_compatible_node(NULL, NULL, "arm,cci-400");
> - if (node && of_device_is_available(node)) {
> - mcpm_smp_set_ops();
> - return true;
> + for_each_possible_cpu(cpu) {
> + bool available;
> +
> + cpu_node = of_get_cpu_node(cpu, NULL);
> + if (WARN(!cpu_node, "Missing cpu device node!"))
> + return false;
> +
> + cci_node = of_parse_phandle(cpu_node, "cci-control-port", 0);
> + available = cci_node && of_device_is_available(cci_node);
> + of_node_put(cci_node);
> + of_node_put(cpu_node);
> +
> + if (!available)
> + return false;
> }
> +
> + mcpm_smp_set_ops();
> + return true;
> #endif
> return false;
> }
^ permalink raw reply
* [PATCH v7] KVM: arm/arm64: Route vtimer events to user space
From: Alexander Graf @ 2016-09-26 12:06 UTC (permalink / raw)
To: linux-arm-kernel
We have 2 modes for dealing with interrupts in the ARM world. We can either
handle them all using hardware acceleration through the vgic or we can emulate
a gic in user space and only drive CPU IRQ pins from there.
Unfortunately, when driving IRQs from user space, we never tell user space
about timer events that may result in interrupt line state changes, so we
lose out on timer events if we run with user space gic emulation.
This patch fixes that by exposing kvm's view of the vtimer irq line to user
space and giving it a chance to sync that when it changes.
With this patch I can successfully run edk2 and Linux with user space gic
emulation.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
v1 -> v2:
- Add back curly brace that got lost
v2 -> v3:
- Split into patch set
v3 -> v4:
- Improve documentation
v4 -> v5:
- Rewrite to use pending state sync in sregs (marc)
- Remove redundant checks of vgic_initialized()
v5 -> v6:
- s/pending/asserted/
- split kvm_timer_flush_hwstate function
- remove user_timer_asserted
- rename kernel_timer_asserted to timer_irq_level
- exit only once per level change
v6 -> v7:
- Move run struct sync out of the run loop
- Only check for run sync in kvm_timer_flush_hwstate()
- qemu tree to try this out: https://github.com/agraf/qemu.git no-kvm-irqchip-for-v6
---
Documentation/virtual/kvm/api.txt | 27 +++++++++
arch/arm/include/uapi/asm/kvm.h | 2 +
arch/arm/kvm/arm.c | 18 +++---
arch/arm64/include/uapi/asm/kvm.h | 2 +
include/kvm/arm_arch_timer.h | 3 +-
include/uapi/linux/kvm.h | 6 ++
virt/kvm/arm/arch_timer.c | 122 ++++++++++++++++++++++++++++++++------
7 files changed, 150 insertions(+), 30 deletions(-)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 739db9a..20ab558 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -3928,3 +3928,30 @@ In order to use SynIC, it has to be activated by setting this
capability via KVM_ENABLE_CAP ioctl on the vcpu fd. Note that this
will disable the use of APIC hardware virtualization even if supported
by the CPU, as it's incompatible with SynIC auto-EOI behavior.
+
+8.3 KVM_CAP_ARM_TIMER
+
+Architectures: arm, arm64
+This capability, if KVM_CHECK_EXTENSION indicates that it is available and no
+in-kernel interrupt controller is in use, means that that the kernel populates
+the vcpu's run->s.regs.timer_irq_level field with timers that are currently
+considered asserted by kvm.
+
+If active, kvm guarantees at least one exit happens after it detects an
+assertion change. This exit could either be a KVM_EXIT_INTR or any other exit
+event, like KVM_EXIT_MMIO. This way kvm gives user space a chance to update its
+own interrupt asserted status. This usually involves triggering an interrupt
+line on a user space emulated interrupt controller, so user space should always
+check the state of run->s.regs.timer_irq_level on every kvm exit.
+
+The field run->s.regs.timer_irq_level is available independent of
+run->kvm_valid_regs or run->kvm_dirty_regs bits. If no in-kernel interrupt
+controller is used and the capability exists, it will always be available and
+populated.
+
+Currently the following bits are defined for the timer_irq_level bitmap:
+
+ KVM_ARM_TIMER_VTIMER - virtual timer
+
+Future versions of kvm may implement additional timer events. These will get
+indicated by additional KVM_CAP extensions.
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index a2b3eb3..ad61b4f 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -105,6 +105,8 @@ struct kvm_debug_exit_arch {
};
struct kvm_sync_regs {
+ /* Used with KVM_CAP_ARM_TIMER */
+ u8 timer_irq_level;
};
struct kvm_arch_memory_slot {
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 75f130e..c4c1734 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -187,6 +187,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_ARM_PSCI_0_2:
case KVM_CAP_READONLY_MEM:
case KVM_CAP_MP_STATE:
+ case KVM_CAP_ARM_TIMER:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
@@ -474,13 +475,7 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
return ret;
}
- /*
- * Enable the arch timers only if we have an in-kernel VGIC
- * and it has been properly initialized, since we cannot handle
- * interrupts from the virtual timer with a userspace gic.
- */
- if (irqchip_in_kernel(kvm) && vgic_initialized(kvm))
- ret = kvm_timer_enable(vcpu);
+ ret = kvm_timer_enable(vcpu);
return ret;
}
@@ -549,7 +544,7 @@ static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu)
*/
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
- int ret;
+ int ret, timer_ret;
sigset_t sigsaved;
if (unlikely(!kvm_vcpu_initialized(vcpu)))
@@ -588,7 +583,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
*/
preempt_disable();
kvm_pmu_flush_hwstate(vcpu);
- kvm_timer_flush_hwstate(vcpu);
+ timer_ret = kvm_timer_flush_hwstate(vcpu);
kvm_vgic_flush_hwstate(vcpu);
local_irq_disable();
@@ -596,7 +591,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
/*
* Re-check atomic conditions
*/
- if (signal_pending(current)) {
+ if (timer_ret || signal_pending(current)) {
ret = -EINTR;
run->exit_reason = KVM_EXIT_INTR;
}
@@ -668,6 +663,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
ret = handle_exit(vcpu, run, ret);
}
+ /* Resynchronize the internal timer and vcpu run irq level bits */
+ kvm_timer_sync_run(vcpu);
+
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
return ret;
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 3051f86..411d62a 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -143,6 +143,8 @@ struct kvm_debug_exit_arch {
#define KVM_GUESTDBG_USE_HW (1 << 17)
struct kvm_sync_regs {
+ /* Used with KVM_CAP_ARM_TIMER */
+ u8 timer_irq_level;
};
struct kvm_arch_memory_slot {
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index dda39d8..cc49bcd 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -63,8 +63,9 @@ void kvm_timer_init(struct kvm *kvm);
int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
const struct kvm_irq_level *irq);
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
-void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu);
+int kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu);
void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu);
+void kvm_timer_sync_run(struct kvm_vcpu *vcpu);
void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu);
u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 300ef25..10d63c5 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -870,6 +870,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_S390_USER_INSTR0 130
#define KVM_CAP_MSI_DEVID 131
#define KVM_CAP_PPC_HTM 132
+#define KVM_CAP_ARM_TIMER 133
#ifdef KVM_CAP_IRQ_ROUTING
@@ -1327,4 +1328,9 @@ struct kvm_assigned_msix_entry {
#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)
#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1)
+/* Available with KVM_CAP_ARM_TIMER */
+
+/* Bits for run->s.regs.{user,kernel}_timer_asserted */
+#define KVM_ARM_TIMER_VTIMER (1 << 0)
+
#endif /* __LINUX_KVM_H */
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 4309b60..62f1daa 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -166,26 +166,69 @@ bool kvm_timer_should_fire(struct kvm_vcpu *vcpu)
return cval <= now;
}
+static bool kvm_timer_in_sync_with_run(struct kvm_vcpu *vcpu)
+{
+ struct kvm_sync_regs *regs = &vcpu->run->s.regs;
+ bool timer_high = vcpu->arch.timer_cpu.irq.level;
+ bool run_high = regs->timer_irq_level & KVM_ARM_TIMER_VTIMER;
+
+ /* Only need to sync with user space irqchip */
+ if (irqchip_in_kernel(vcpu->kvm))
+ return true;
+
+ return timer_high == run_high;
+}
+
+/*
+ * Synchronize the vcpu run irq level bits with the timer
+ */
+void kvm_timer_sync_run(struct kvm_vcpu *vcpu)
+{
+ struct kvm_sync_regs *regs = &vcpu->run->s.regs;
+
+ /* Only synchronize if we're out of sync */
+ if (kvm_timer_in_sync_with_run(vcpu))
+ return;
+
+ /* Populate the timer bitmap for user space */
+ regs->timer_irq_level &= ~KVM_ARM_TIMER_VTIMER;
+ if (vcpu->arch.timer_cpu.irq.level)
+ regs->timer_irq_level |= KVM_ARM_TIMER_VTIMER;
+}
+
+/*
+ * Synchronize the timer IRQ state with the interrupt controller.
+ */
static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
{
int ret;
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
- BUG_ON(!vgic_initialized(vcpu->kvm));
-
timer->active_cleared_last = false;
timer->irq.level = new_level;
- trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
+ trace_kvm_timer_update_irq(vcpu->vcpu_id, host_vtimer_irq,
timer->irq.level);
- ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
- timer->irq.irq,
- timer->irq.level);
- WARN_ON(ret);
+
+ if (irqchip_in_kernel(vcpu->kvm)) {
+ BUG_ON(!vgic_initialized(vcpu->kvm));
+
+ /* Fire the timer in the VGIC */
+ ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
+ timer->irq.irq,
+ timer->irq.level);
+
+ WARN_ON(ret);
+ }
}
/*
* Check if there was a change in the timer state (should we raise or lower
* the line level to the GIC).
+ *
+ * Returns:
+ *
+ * <0 - error
+ * 0 - success
*/
static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
{
@@ -197,7 +240,8 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
* because the guest would never see the interrupt. Instead wait
* until we call this function from kvm_timer_flush_hwstate.
*/
- if (!vgic_initialized(vcpu->kvm) || !timer->enabled)
+ if ((irqchip_in_kernel(vcpu->kvm) && !vgic_initialized(vcpu->kvm)) ||
+ !timer->enabled)
return -ENODEV;
if (kvm_timer_should_fire(vcpu) != timer->irq.level)
@@ -242,22 +286,12 @@ void kvm_timer_unschedule(struct kvm_vcpu *vcpu)
timer_disarm(timer);
}
-/**
- * kvm_timer_flush_hwstate - prepare to move the virt timer to the cpu
- * @vcpu: The vcpu pointer
- *
- * Check if the virtual timer has expired while we were running in the host,
- * and inject an interrupt if that was the case.
- */
-void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
+static void kvm_timer_flush_hwstate_vgic(struct kvm_vcpu *vcpu)
{
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
bool phys_active;
int ret;
- if (kvm_timer_update_state(vcpu))
- return;
-
/*
* If we enter the guest with the virtual input level to the VGIC
* asserted, then we have already told the VGIC what we need to, and
@@ -309,6 +343,51 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
timer->active_cleared_last = !phys_active;
}
+static void kvm_timer_flush_hwstate_user(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+ /*
+ * As long as the timer is asserted, we do not need to get new host
+ * timer events to know whether the line is still up. Since the GIC
+ * is handled in user space, we will get an exit on EOI, so we can
+ * resynchronize the status there.
+ */
+ if (timer->irq.level)
+ disable_percpu_irq(host_vtimer_irq);
+ else
+ enable_percpu_irq(host_vtimer_irq, 0);
+}
+
+/**
+ * kvm_timer_flush_hwstate - prepare to move the virt timer to the cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Check if the virtual timer has expired while we were running in the host,
+ * and inject an interrupt if that was the case.
+ *
+ * Returns:
+ *
+ * 0 - success
+ * 1 - need exit to user space
+ */
+int kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+ if (kvm_timer_update_state(vcpu))
+ return 0;
+
+ /* Do we need to return to user space to resynchronize? */
+ if (!kvm_timer_in_sync_with_run(vcpu))
+ return 1;
+
+ if (irqchip_in_kernel(vcpu->kvm))
+ kvm_timer_flush_hwstate_vgic(vcpu);
+ else
+ kvm_timer_flush_hwstate_user(vcpu);
+
+ return 0;
+}
+
/**
* kvm_timer_sync_hwstate - sync timer state from cpu
* @vcpu: The vcpu pointer
@@ -479,6 +558,10 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
if (timer->enabled)
return 0;
+ /* No need to route physical IRQs when we don't use the vgic */
+ if (!irqchip_in_kernel(vcpu->kvm))
+ goto no_vgic;
+
/*
* Find the physical IRQ number corresponding to the host_vtimer_irq
*/
@@ -502,6 +585,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
if (ret)
return ret;
+no_vgic:
/*
* There is a potential race here between VCPUs starting for the first
--
1.8.5.6
^ permalink raw reply related
* [PATCH] serial: stm32: mark symbols static where possible
From: Baoyou Xie @ 2016-09-26 11:58 UTC (permalink / raw)
To: linux-arm-kernel
We get 2 warnings when building kernel with W=1:
drivers/tty/serial/stm32-usart.c:63:5: warning: no previous prototype for 'stm32_pending_rx' [-Wmissing-prototypes]
drivers/tty/serial/stm32-usart.c:88:15: warning: no previous prototype for 'stm32_get_char' [-Wmissing-prototypes]
In fact, these two functions are only used in the file in which they are
declared and don't need a declaration, but can be made static.
So this patch marks these functions with 'static'.
Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
drivers/tty/serial/stm32-usart.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 4d3001b..bb9b5e9 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -60,8 +60,8 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
writel_relaxed(val, port->membase + reg);
}
-int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
- bool threaded)
+static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
+ bool threaded)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
@@ -85,7 +85,8 @@ int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
return 0;
}
-unsigned long stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
+static unsigned long
+stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
--
2.7.4
^ permalink raw reply related
* [PATCHv2 1/3] serial: mctrl_gpio: implement mctrl_gpio_use_rtscts
From: Richard Genoud @ 2016-09-26 11:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160922131405.y4wvgd3n534jbdv5@pengutronix.de>
2016-09-22 15:14 GMT+02:00 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
> On Mon, Sep 12, 2016 at 11:47:31AM +0200, Richard Genoud wrote:
>> This function returns true if CTS and RTS are used as GPIOs.
>> Some drivers (like atmel_serial) needs to know if the flow control is
>> handled by the controller or by GPIOs.
>>
>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>> ---
>> drivers/tty/serial/serial_mctrl_gpio.c | 8 ++++++++
>> drivers/tty/serial/serial_mctrl_gpio.h | 10 ++++++++++
>> 2 files changed, 18 insertions(+)
>>
>> diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
>> index d2da6aa7f27d..93bed8c99796 100644
>> --- a/drivers/tty/serial/serial_mctrl_gpio.c
>> +++ b/drivers/tty/serial/serial_mctrl_gpio.c
>> @@ -17,6 +17,7 @@
>> #include <linux/err.h>
>> #include <linux/device.h>
>> #include <linux/irq.h>
>> +#include <linux/err.h>
>> #include <linux/gpio/consumer.h>
>> #include <linux/termios.h>
>> #include <linux/serial_core.h>
>> @@ -72,6 +73,13 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
>> }
>> EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
>>
>> +bool mctrl_gpio_use_rtscts(struct mctrl_gpios *gpios)
>> +{
>> + return !IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS)) &&
>> + !IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_RTS));
>
> mctrl_gpio_to_gpiod cannot return an error pointer. So this is
> (surprise!) a wrong usage of IS_ERR_OR_NULL.
I see, your commit 1d267ea6539f266352f ("serial: mctrl-gpio: simplify
init routine") removed the need of IS_ERR_OR_NULL().
I'll change that.
Thanks !
Richard.
^ permalink raw reply
* Re: [PATCH V5 3/4] drm/bridge: Add driver for GE B850v3 LVDS/DP++ Bridge
From: Peter Senna Tschudin @ 2016-09-26 11:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <180ae266-a4fb-4432-83dc-e39f2ccb0ad1@codeaurora.org>
On Monday, September 26, 2016 12:29 CEST, Archit Taneja <architt@codeaurora.org> wrote:
> Hi,
>
> Some comments.
Thank you for the review!
>
> On 08/09/2016 10:11 PM, Peter Senna Tschudin wrote:
> > Add a driver that create a drm_bridge and a drm_connector for the LVDS
> > to DP++ display bridge of the GE B850v3.
> >
> > There are two physical bridges on the video signal pipeline: a
> > STDP4028(LVDS to DP) and a STDP2690(DP to DP++). The hardware and
> > firmware made it complicated for this binding to comprise two device
> > tree nodes, as the design goal is to configure both bridges based on
> > the LVDS signal, which leave the driver powerless to control the video
> > processing pipeline. The two bridges behaves as a single bridge, and
> > the driver is only needed for telling the host about EDID / HPD, and
> > for giving the host powers to ack interrupts. The video signal pipeline
> > is as follows:
> >
> > Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
> >
> > Cc: Martyn Welch <martyn.welch@collabora.co.uk>
> > Cc: Martin Donnelly <martin.donnelly@ge.com>
> > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> > Cc: Philipp Zabel <p.zabel@pengutronix.de>
> > Cc: Rob Herring <robh@kernel.org>
> > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > CC: David Airlie <airlied@linux.ie>
> > CC: Thierry Reding <treding@nvidia.com>
> > CC: Thierry Reding <thierry.reding@gmail.com>
> > Reviewed-by: Enric Balletbo <enric.balletbo@collabora.com>
> > Signed-off-by: Peter Senna Tschudin <peter.senna@collabora.com>
> > ---
> > Changes from V4:
> > - Check the output of the first call to i2c_smbus_write_word_data() and return
> > it's error code for failing gracefully on i2c issues
> > - Renamed the i2c_driver.name from "ge,b850v3-lvds-dp" to "b850v3-lvds-dp" to
> > remove the comma from the driver name
> >
> > Changes from V3:
> > - 3/4 instead of 4/5
> > - Tested on next-20160804
> >
> > Changes from V2:
> > - Made it atomic to be applied on next-20160729 on top of Liu Ying changes
> > that made imx-ldb atomic
> >
> > Changes from V1:
> > - New commit message
> > - Removed 3 empty entry points
> > - Removed memory leak from ge_b850v3_lvds_dp_get_modes()
> > - Added a lock for mode setting
> > - Removed a few blank lines
> > - Changed the order at Makefile and Kconfig
> >
> > MAINTAINERS | 8 +
> > drivers/gpu/drm/bridge/Kconfig | 11 +
> > drivers/gpu/drm/bridge/Makefile | 1 +
> > drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c | 405 +++++++++++++++++++++++++++++
> > 4 files changed, 425 insertions(+)
> > create mode 100644 drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index a306795..e8d106a 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -5142,6 +5142,14 @@ W: https://linuxtv.org
> > S: Maintained
> > F: drivers/media/radio/radio-gemtek*
> >
> > +GENERAL ELECTRIC B850V3 LVDS/DP++ BRIDGE
> > +M: Peter Senna Tschudin <peter.senna@collabora.com>
> > +M: Martin Donnelly <martin.donnelly@ge.com>
> > +M: Martyn Welch <martyn.welch@collabora.co.uk>
> > +S: Maintained
> > +F: drivers/gpu/drm/bridge/ge_b850v3_dp2.c
> > +F: Documentation/devicetree/bindings/ge/b850v3_dp2_bridge.txt
> > +
> > GENERIC GPIO I2C DRIVER
> > M: Haavard Skinnemoen <hskinnemoen@gmail.com>
> > S: Supported
>
> Could you move the MAINTAINERS change to a different patch? It would
> make it easier to integrate separately.
If needed, yes sure.
>
> > diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> > index b590e67..b4b70fb 100644
> > --- a/drivers/gpu/drm/bridge/Kconfig
> > +++ b/drivers/gpu/drm/bridge/Kconfig
> > @@ -32,6 +32,17 @@ config DRM_DW_HDMI_AHB_AUDIO
> > Designware HDMI block. This is used in conjunction with
> > the i.MX6 HDMI driver.
> >
> > +config DRM_GE_B850V3_LVDS_DP
> > + tristate "GE B850v3 LVDS to DP++ display bridge"
> > + depends on OF
> > + select DRM_KMS_HELPER
> > + select DRM_PANEL
> > + ---help---
> > + This is a driver for the display bridge of
> > + GE B850v3 that convert dual channel LVDS
> > + to DP++. This is used with the i.MX6 imx-ldb
> > + driver.
> > +
> > config DRM_NXP_PTN3460
> > tristate "NXP PTN3460 DP/LVDS bridge"
> > depends on OF
> > diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> > index efdb07e..b9606f3 100644
> > --- a/drivers/gpu/drm/bridge/Makefile
> > +++ b/drivers/gpu/drm/bridge/Makefile
> > @@ -3,6 +3,7 @@ ccflags-y := -Iinclude/drm
> > obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
> > obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
> > obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
> > +obj-$(CONFIG_DRM_GE_B850V3_LVDS_DP) += ge_b850v3_lvds_dp.o
> > obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
> > obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
> > obj-$(CONFIG_DRM_SII902X) += sii902x.o
> > diff --git a/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
> > new file mode 100644
> > index 0000000..81e9279
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
> > @@ -0,0 +1,405 @@
> > +/*
> > + * Driver for GE B850v3 DP display bridge
> > +
> > + * Copyright (c) 2016, Collabora Ltd.
> > + * Copyright (c) 2016, General Electric Company
> > +
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2, as published by the Free Software Foundation.
> > +
> > + * This program is distributed in the hope 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.
> > +
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> > +
> > + * This driver creates a drm_bridge and a drm_connector for the LVDS to DP++
> > + * display bridge of the GE B850v3. There are two physical bridges on the video
> > + * signal pipeline: a STDP4028(LVDS to DP) and a STDP2690(DP to DP++). However
> > + * the physical bridges are automatically configured by the input video signal,
> > + * and the driver has no access to the video processing pipeline. The driver is
> > + * only needed to read EDID from the STDP2690 and to handle HPD events from the
> > + * STDP4028. The driver communicates with both bridges over i2c. The video
> > + * signal pipeline is as follows:
> > + *
> > + * Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
> > + *
> > + */
> > +
> > +#include <linux/gpio.h>
> > +#include <linux/i2c.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_crtc_helper.h>
> > +#include <drm/drm_edid.h>
> > +#include <drm/drmP.h>
> > +
> > +/*
> > + * 220Mhz is a limitation of the host, as the bridge is capable of up to
> > + * 330Mhz. See section 9.2.1.2.4 of the i.MX 6Dual/6Quad Applications
> > + * Processor Reference Manual for more information about the 220Mhz limit.
> > + * The imx-ldb driver will warn about clocks over 170Mhz, but it seem to work
> > + * fine.
> > + */
> > +#define MAX_PIXEL_CLOCK 220000
> > +
> > +#define EDID_EXT_BLOCK_CNT 0x7E
> > +
> > +#define STDP4028_IRQ_OUT_CONF_REG 0x02
> > +#define STDP4028_DPTX_IRQ_EN_REG 0x3C
> > +#define STDP4028_DPTX_IRQ_STS_REG 0x3D
> > +#define STDP4028_DPTX_STS_REG 0x3E
> > +
> > +#define STDP4028_DPTX_DP_IRQ_EN 0x1000
> > +
> > +#define STDP4028_DPTX_HOTPLUG_IRQ_EN 0x0400
> > +#define STDP4028_DPTX_LINK_CH_IRQ_EN 0x2000
> > +#define STDP4028_DPTX_IRQ_CONFIG \
> > + (STDP4028_DPTX_LINK_CH_IRQ_EN | STDP4028_DPTX_HOTPLUG_IRQ_EN)
> > +
> > +#define STDP4028_DPTX_HOTPLUG_STS 0x0200
> > +#define STDP4028_DPTX_LINK_STS 0x1000
> > +#define STDP4028_CON_STATE_CONNECTED \
> > + (STDP4028_DPTX_HOTPLUG_STS | STDP4028_DPTX_LINK_STS)
> > +
> > +#define STDP4028_DPTX_HOTPLUG_CH_STS 0x0400
> > +#define STDP4028_DPTX_LINK_CH_STS 0x2000
> > +#define STDP4028_DPTX_IRQ_CLEAR \
> > + (STDP4028_DPTX_LINK_CH_STS | STDP4028_DPTX_HOTPLUG_CH_STS)
> > +
> > +struct ge_b850v3_lvds_dp {
> > + struct drm_connector connector;
> > + struct drm_bridge bridge;
> > + struct i2c_client *ge_b850v3_lvds_dp_i2c;
> > + struct i2c_client *edid_i2c;
> > + struct edid *edid;
> > + struct mutex lock;
> > +};
> > +
> > +static inline struct ge_b850v3_lvds_dp *
> > + bridge_to_ge_b850v3_lvds_dp(struct drm_bridge *bridge)
> > +{
> > + return container_of(bridge, struct ge_b850v3_lvds_dp, bridge);
> > +}
> > +
> > +static inline struct ge_b850v3_lvds_dp *
> > + connector_to_ge_b850v3_lvds_dp(struct drm_connector *connector)
> > +{
> > + return container_of(connector, struct ge_b850v3_lvds_dp, connector);
> > +}
> > +
> > +u8 *stdp2690_get_edid(struct i2c_client *client)
> > +{
> > + struct i2c_adapter *adapter = client->adapter;
> > + unsigned char start = 0x00;
> > + unsigned int total_size;
> > + u8 *block = kmalloc(EDID_LENGTH, GFP_KERNEL);
> > +
> > + struct i2c_msg msgs[] = {
> > + {
> > + .addr = client->addr,
> > + .flags = 0,
> > + .len = 1,
> > + .buf = &start,
> > + }, {
> > + .addr = client->addr,
> > + .flags = I2C_M_RD,
> > + .len = EDID_LENGTH,
> > + .buf = block,
> > + }
> > + };
> > +
> > + if (!block)
> > + return NULL;
> > +
> > + if (i2c_transfer(adapter, msgs, 2) != 2) {
> > + DRM_ERROR("Unable to read EDID.\n");
> > + goto err;
> > + }
> > +
> > + if (!drm_edid_block_valid(block, 0, false, NULL)) {
> > + DRM_ERROR("Invalid EDID block\n");
> > + goto err;
> > + }
> > +
> > + total_size = (block[EDID_EXT_BLOCK_CNT] + 1) * EDID_LENGTH;
> > + if (total_size > EDID_LENGTH) {
> > + kfree(block);
> > + block = kmalloc(total_size, GFP_KERNEL);
> > + if (!block)
> > + return NULL;
> > +
> > + /* Yes, read the entire buffer, and do not skip the first
> > + * EDID_LENGTH bytes.
> > + */
> > + start = 0x00;
> > + msgs[1].len = total_size;
> > + msgs[1].buf = block;
> > +
> > + if (i2c_transfer(adapter, msgs, 2) != 2) {
> > + DRM_ERROR("Unable to read EDID extension blocks.\n");
> > + goto err;
> > + }
> > + }
> > +
> > + return block;
> > +
> > +err:
> > + kfree(block);
> > + return NULL;
> > +}
> > +
> > +static int ge_b850v3_lvds_dp_get_modes(struct drm_connector *connector)
> > +{
> > + struct ge_b850v3_lvds_dp *ptn_bridge;
> > + struct i2c_client *client;
> > + int num_modes = 0;
> > +
> > + ptn_bridge = connector_to_ge_b850v3_lvds_dp(connector);
> > + client = ptn_bridge->edid_i2c;
> > +
> > + mutex_lock(&ptn_bridge->lock);
> > +
> > + kfree(ptn_bridge->edid);
> > + ptn_bridge->edid = (struct edid *) stdp2690_get_edid(client);
> > +
> > + if (ptn_bridge->edid) {
> > + drm_mode_connector_update_edid_property(connector,
> > + ptn_bridge->edid);
> > + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
> > + }
> > +
> > + mutex_unlock(&ptn_bridge->lock);
> > +
> > + return num_modes;
> > +}
> > +
> > +
> > +static enum drm_mode_status ge_b850v3_lvds_dp_mode_valid(
> > + struct drm_connector *connector, struct drm_display_mode *mode)
> > +{
> > + if (mode->clock > MAX_PIXEL_CLOCK) {
> > + DRM_INFO("The pixel clock for the mode %s is too high, and not supported.",
> > + mode->name);
> > + return MODE_CLOCK_HIGH;
> > + }
> > +
> > + return MODE_OK;
> > +}
> > +
> > +static const struct
> > +drm_connector_helper_funcs ge_b850v3_lvds_dp_connector_helper_funcs = {
> > + .get_modes = ge_b850v3_lvds_dp_get_modes,
> > + .mode_valid = ge_b850v3_lvds_dp_mode_valid,
> > +};
> > +
> > +static enum drm_connector_status ge_b850v3_lvds_dp_detect(
> > + struct drm_connector *connector, bool force)
> > +{
> > + struct ge_b850v3_lvds_dp *ptn_bridge =
> > + connector_to_ge_b850v3_lvds_dp(connector);
> > + struct i2c_client *ge_b850v3_lvds_dp_i2c =
> > + ptn_bridge->ge_b850v3_lvds_dp_i2c;
> > + s32 link_state;
> > +
> > + link_state = i2c_smbus_read_word_data(ge_b850v3_lvds_dp_i2c,
> > + STDP4028_DPTX_STS_REG);
> > +
> > + if (link_state == STDP4028_CON_STATE_CONNECTED)
> > + return connector_status_connected;
> > +
> > + if (link_state == 0)
> > + return connector_status_disconnected;
> > +
> > + return connector_status_unknown;
> > +}
> > +
> > +static const struct drm_connector_funcs ge_b850v3_lvds_dp_connector_funcs = {
> > + .dpms = drm_atomic_helper_connector_dpms,
> > + .fill_modes = drm_helper_probe_single_connector_modes,
> > + .detect = ge_b850v3_lvds_dp_detect,
> > + .destroy = drm_connector_cleanup,
> > + .reset = drm_atomic_helper_connector_reset,
> > + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> > + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> > +};
> > +
> > +static irqreturn_t ge_b850v3_lvds_dp_irq_handler(int irq, void *dev_id)
> > +{
> > + struct ge_b850v3_lvds_dp *ptn_bridge = dev_id;
> > + struct i2c_client *ge_b850v3_lvds_dp_i2c
> > + = ptn_bridge->ge_b850v3_lvds_dp_i2c;
> > +
> > + mutex_lock(&ptn_bridge->lock);
> > +
> > + i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
> > + STDP4028_DPTX_IRQ_STS_REG, STDP4028_DPTX_IRQ_CLEAR);
> > +
> > + mutex_unlock(&ptn_bridge->lock);
> > +
> > + if (ptn_bridge->connector.dev)
> > + drm_kms_helper_hotplug_event(ptn_bridge->connector.dev);
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static int ge_b850v3_lvds_dp_attach(struct drm_bridge *bridge)
> > +{
> > + struct ge_b850v3_lvds_dp *ptn_bridge
> > + = bridge_to_ge_b850v3_lvds_dp(bridge);
> > + struct drm_connector *connector = &ptn_bridge->connector;
> > + struct i2c_client *ge_b850v3_lvds_dp_i2c
> > + = ptn_bridge->ge_b850v3_lvds_dp_i2c;
> > + int ret;
> > +
> > + if (!bridge->encoder) {
> > + DRM_ERROR("Parent encoder object not found");
> > + return -ENODEV;
> > + }
> > +
> > + connector->polled = DRM_CONNECTOR_POLL_HPD;
> > +
> > + drm_connector_helper_add(connector,
> > + &ge_b850v3_lvds_dp_connector_helper_funcs);
> > +
> > + ret = drm_connector_init(bridge->dev, connector,
> > + &ge_b850v3_lvds_dp_connector_funcs,
> > + DRM_MODE_CONNECTOR_DisplayPort);
> > + if (ret) {
> > + DRM_ERROR("Failed to initialize connector with drm\n");
> > + return ret;
> > + }
> > +
> > + drm_connector_register(connector);
>
> Connectors shouldn't be registered in the bridge driver, they should
> be registered by the kms driver after drm_dev_register is called.
> The drm_connector_register_all() API is used for that.
Hmm, I got this from:
drivers/gpu/drm/bridge/nxp-ptn3460.c: drm_connector_register(&ptn_bridge->connector);
drivers/gpu/drm/bridge/parade-ps8622.c: drm_connector_register(&ps8622->connector);
drivers/gpu/drm/bridge/analogix-anx78xx.c: err = drm_connector_register(&anx78xx->connector);
>
> > + ret = drm_mode_connector_attach_encoder(connector, bridge->encoder);
> > + if (ret)
> > + return ret;
> > +
> > + drm_bridge_enable(bridge);
>
> This drm_bridge_enable() doesn't seem to serve any purpose here. It also
> doesn't seem to make much sense to call drm_bridge_() funcs within a
> bridge op itself.
Yes, removing this line has no effect. I'll send V6. Thank you!
>
> > + if (ge_b850v3_lvds_dp_i2c->irq) {
> > + drm_helper_hpd_irq_event(connector->dev);
> > +
> > + ret = devm_request_threaded_irq(&ge_b850v3_lvds_dp_i2c->dev,
> > + ge_b850v3_lvds_dp_i2c->irq, NULL,
> > + ge_b850v3_lvds_dp_irq_handler,
> > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> > + "ge-b850v3-lvds-dp", ptn_bridge);
>
> Is there a reason why we register the interrupt handler here and not in
> probe?
Yes, drm_bridge_funcs.attach() is called when drm decides it is time to initialize the bridge, which means the drm is already running. i2c_driver.probe() is likely to be called way before drm initializes, and if for some reason the bridge is not attached, there is no need for the interrupt handler. In this case the interrupt handler is mostly used for events related to display plugging/unplugging.
^ permalink raw reply
* [PATCH 5/5] arm64: Add uprobe support
From: Catalin Marinas @ 2016-09-26 11:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAHB_GupuUYPNFoYQeX8EhAcesvqKVVuphuxneudZ5kL2cxm-7g@mail.gmail.com>
On Sun, Sep 25, 2016 at 10:32:28PM +0530, Pratyush Anand wrote:
> On Fri, Sep 23, 2016 at 6:35 PM, Catalin Marinas
> <catalin.marinas@arm.com> wrote:
> > On Fri, Sep 23, 2016 at 09:42:30AM +0530, Pratyush Anand wrote:
> >> On 22/09/2016:05:50:30 PM, Catalin Marinas wrote:
> >> > On Thu, Sep 22, 2016 at 08:53:28AM +0530, Pratyush Anand wrote:
> >> > > On 21/09/2016:06:04:04 PM, Catalin Marinas wrote:
>
> >> > As a quick workaround you could check mm->task_size > TASK_SIZE_32 in
> >> > the arch_uprobe_analyze_insn() function.
> >>
> >> It would be doable. TASK_SIZE_32 is defined only for COMPAT. So, may be I can
> >> return -EINVAL when mm->task_size < TASK_SIZE_64.
> >
> > That's just a temporary workaround. If we ever merge ILP32, this test
> > would no longer be enough (as the ISA is AArch64 but with TASK_SIZE_32).
>
> OK.. So what about doing something similar what x86 is doing.
> We can have a flag for task Type in arch specific mm_context_t. We
> also set this flag in COMPAT_SET_PERSONALITY() along with setting
> thread_info flag, and we clear them in SET_PERSONALITY().
This looks like a better approach.
> > Looking at prepare_uprobe(), we have a weak is_trap_insn() function.
> > This check is meaningless without knowing which instruction set we
> > target. A false positive here, however, is not that bad as we wouldn't
> > end up inserting the wrong breakpoint in the executable. But it looks to
> > me like the core uprobe code needs to pass some additional information
> > like the type of task or ELF format to the arch code to make a useful
> > choice of breakpoint type.
>
> It seems that 'strtle r0, [r0], #160' would have the closest matching
> aarch32 instruction wrt BRK64_OPCODE_UPROBES(0xd42000A0). But that too
> seems a bad instruction. So, may be we can use still weak
> is_trap_insn().
Even if the is_trap_insn() check passes, we would reject the probe in
arch_uprobe_analyze_insn() immediately after based on the mm type check,
so not too bad.
If we add support for probing 32-bit tasks, I would rather have
is_trap_insn() take the mm_struct as argument so that a non-weak
implementation can check for the correct encoding.
--
Catalin
^ permalink raw reply
* [PATCH] usb: gadget: udc: atmel: fix endpoint name
From: Richard Genoud @ 2016-09-26 10:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <874m535dti.fsf@linux.intel.com>
2016-09-26 9:18 GMT+02:00 Felipe Balbi <balbi@kernel.org>:
>
> Hi,
>
> Greg Kroah-Hartman <gregkh@linuxfoundation.org> writes:
>> On Fri, Sep 23, 2016 at 04:20:45PM +0200, Nicolas Ferre wrote:
>>> Le 16/09/2016 ? 10:36, Nicolas Ferre a ?crit :
>>> > Le 15/09/2016 ? 17:07, Alexandre Belloni a ?crit :
>>> >> Since commit c32b5bcfa3c4 ("ARM: dts: at91: Fix USB endpoint nodes"),
>>> >> atmel_usba_udc fails with:
>>> >>
>>> >> ------------[ cut here ]------------
>>> >> WARNING: CPU: 0 PID: 0 at include/linux/usb/gadget.h:405
>>> >> ecm_do_notify+0x188/0x1a0
>>> >> Modules linked in:
>>> >> CPU: 0 PID: 0 Comm: swapper Not tainted 4.7.0+ #15
>>> >> Hardware name: Atmel SAMA5
>>> >> [<c010ccfc>] (unwind_backtrace) from [<c010a7ec>] (show_stack+0x10/0x14)
>>> >> [<c010a7ec>] (show_stack) from [<c0115c10>] (__warn+0xe4/0xfc)
>>> >> [<c0115c10>] (__warn) from [<c0115cd8>] (warn_slowpath_null+0x20/0x28)
>>> >> [<c0115cd8>] (warn_slowpath_null) from [<c04377ac>] (ecm_do_notify+0x188/0x1a0)
>>> >> [<c04377ac>] (ecm_do_notify) from [<c04379a4>] (ecm_set_alt+0x74/0x1ac)
>>> >> [<c04379a4>] (ecm_set_alt) from [<c042f74c>] (composite_setup+0xfc0/0x19f8)
>>> >> [<c042f74c>] (composite_setup) from [<c04356e8>] (usba_udc_irq+0x8f4/0xd9c)
>>> >> [<c04356e8>] (usba_udc_irq) from [<c013ec9c>] (handle_irq_event_percpu+0x9c/0x158)
>>> >> [<c013ec9c>] (handle_irq_event_percpu) from [<c013ed80>] (handle_irq_event+0x28/0x3c)
>>> >> [<c013ed80>] (handle_irq_event) from [<c01416d4>] (handle_fasteoi_irq+0xa0/0x168)
>>> >> [<c01416d4>] (handle_fasteoi_irq) from [<c013e3f8>] (generic_handle_irq+0x24/0x34)
>>> >> [<c013e3f8>] (generic_handle_irq) from [<c013e640>] (__handle_domain_irq+0x54/0xa8)
>>> >> [<c013e640>] (__handle_domain_irq) from [<c010b214>] (__irq_svc+0x54/0x70)
>>> >> [<c010b214>] (__irq_svc) from [<c0107eb0>] (arch_cpu_idle+0x38/0x3c)
>>> >> [<c0107eb0>] (arch_cpu_idle) from [<c0137300>] (cpu_startup_entry+0x9c/0xdc)
>>> >> [<c0137300>] (cpu_startup_entry) from [<c0900c40>] (start_kernel+0x354/0x360)
>>> >> [<c0900c40>] (start_kernel) from [<20008078>] (0x20008078)
>>> >> ---[ end trace e7cf9dcebf4815a6 ]---
>>> >>
>>> >> Fixes: c32b5bcfa3c4 ("ARM: dts: at91: Fix USB endpoint nodes")
>>> >> Reported-by: Richard Genoud <richard.genoud@gmail.com>
>>> >> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
>>> >
>>> > Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
>>> >
>>> > Felipe, Greg,
>>> > It is clearly a regression and material for 4.8-fixes. But I do know
>>> > that we are very late in the process :-(
>>> > Please do what you can to make it progress before 4.8-final but I'm
>>> > truly aware of the challenge.
>>>
>>> Any chance that we can have it (aka ping)?
>>
>> It's Felipe's area, not mine :)
>
> Sorry, I had missed this one. Greg, seems like this would be the only
> pending fix. Do you want it in a pull request or would you prefer to
> just pick it up as a patch? Works either way for me. In case you decide
> to pick it up as a patch:
>
> Acked-by: Felipe Balbi <felipe.balbi@linux.intel.com>
>
> If you prefer to pick it up as a pull request, I already have the patch
> in my 'fixes' branch, just need to tag it and send it to you.
>
> --
> balbi
All seems ok, thanks Alexandre.
Tested-by: Richard Genoud <richard.genoud@gmail.com>
^ permalink raw reply
* [PATCH V5 3/4] drm/bridge: Add driver for GE B850v3 LVDS/DP++ Bridge
From: Archit Taneja @ 2016-09-26 10:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <37d177d89841be8ff8eec395e3267d1ebf0dfc54.1470739193.git.peter.senna@collabora.com>
Hi,
Some comments.
On 08/09/2016 10:11 PM, Peter Senna Tschudin wrote:
> Add a driver that create a drm_bridge and a drm_connector for the LVDS
> to DP++ display bridge of the GE B850v3.
>
> There are two physical bridges on the video signal pipeline: a
> STDP4028(LVDS to DP) and a STDP2690(DP to DP++). The hardware and
> firmware made it complicated for this binding to comprise two device
> tree nodes, as the design goal is to configure both bridges based on
> the LVDS signal, which leave the driver powerless to control the video
> processing pipeline. The two bridges behaves as a single bridge, and
> the driver is only needed for telling the host about EDID / HPD, and
> for giving the host powers to ack interrupts. The video signal pipeline
> is as follows:
>
> Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
>
> Cc: Martyn Welch <martyn.welch@collabora.co.uk>
> Cc: Martin Donnelly <martin.donnelly@ge.com>
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Cc: Philipp Zabel <p.zabel@pengutronix.de>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> CC: David Airlie <airlied@linux.ie>
> CC: Thierry Reding <treding@nvidia.com>
> CC: Thierry Reding <thierry.reding@gmail.com>
> Reviewed-by: Enric Balletbo <enric.balletbo@collabora.com>
> Signed-off-by: Peter Senna Tschudin <peter.senna@collabora.com>
> ---
> Changes from V4:
> - Check the output of the first call to i2c_smbus_write_word_data() and return
> it's error code for failing gracefully on i2c issues
> - Renamed the i2c_driver.name from "ge,b850v3-lvds-dp" to "b850v3-lvds-dp" to
> remove the comma from the driver name
>
> Changes from V3:
> - 3/4 instead of 4/5
> - Tested on next-20160804
>
> Changes from V2:
> - Made it atomic to be applied on next-20160729 on top of Liu Ying changes
> that made imx-ldb atomic
>
> Changes from V1:
> - New commit message
> - Removed 3 empty entry points
> - Removed memory leak from ge_b850v3_lvds_dp_get_modes()
> - Added a lock for mode setting
> - Removed a few blank lines
> - Changed the order at Makefile and Kconfig
>
> MAINTAINERS | 8 +
> drivers/gpu/drm/bridge/Kconfig | 11 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c | 405 +++++++++++++++++++++++++++++
> 4 files changed, 425 insertions(+)
> create mode 100644 drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a306795..e8d106a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -5142,6 +5142,14 @@ W: https://linuxtv.org
> S: Maintained
> F: drivers/media/radio/radio-gemtek*
>
> +GENERAL ELECTRIC B850V3 LVDS/DP++ BRIDGE
> +M: Peter Senna Tschudin <peter.senna@collabora.com>
> +M: Martin Donnelly <martin.donnelly@ge.com>
> +M: Martyn Welch <martyn.welch@collabora.co.uk>
> +S: Maintained
> +F: drivers/gpu/drm/bridge/ge_b850v3_dp2.c
> +F: Documentation/devicetree/bindings/ge/b850v3_dp2_bridge.txt
> +
> GENERIC GPIO I2C DRIVER
> M: Haavard Skinnemoen <hskinnemoen@gmail.com>
> S: Supported
Could you move the MAINTAINERS change to a different patch? It would
make it easier to integrate separately.
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index b590e67..b4b70fb 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -32,6 +32,17 @@ config DRM_DW_HDMI_AHB_AUDIO
> Designware HDMI block. This is used in conjunction with
> the i.MX6 HDMI driver.
>
> +config DRM_GE_B850V3_LVDS_DP
> + tristate "GE B850v3 LVDS to DP++ display bridge"
> + depends on OF
> + select DRM_KMS_HELPER
> + select DRM_PANEL
> + ---help---
> + This is a driver for the display bridge of
> + GE B850v3 that convert dual channel LVDS
> + to DP++. This is used with the i.MX6 imx-ldb
> + driver.
> +
> config DRM_NXP_PTN3460
> tristate "NXP PTN3460 DP/LVDS bridge"
> depends on OF
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index efdb07e..b9606f3 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -3,6 +3,7 @@ ccflags-y := -Iinclude/drm
> obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
> obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
> obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
> +obj-$(CONFIG_DRM_GE_B850V3_LVDS_DP) += ge_b850v3_lvds_dp.o
> obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
> obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
> obj-$(CONFIG_DRM_SII902X) += sii902x.o
> diff --git a/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
> new file mode 100644
> index 0000000..81e9279
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
> @@ -0,0 +1,405 @@
> +/*
> + * Driver for GE B850v3 DP display bridge
> +
> + * Copyright (c) 2016, Collabora Ltd.
> + * Copyright (c) 2016, General Electric Company
> +
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> +
> + * This program is distributed in the hope 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.
> +
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> + * This driver creates a drm_bridge and a drm_connector for the LVDS to DP++
> + * display bridge of the GE B850v3. There are two physical bridges on the video
> + * signal pipeline: a STDP4028(LVDS to DP) and a STDP2690(DP to DP++). However
> + * the physical bridges are automatically configured by the input video signal,
> + * and the driver has no access to the video processing pipeline. The driver is
> + * only needed to read EDID from the STDP2690 and to handle HPD events from the
> + * STDP4028. The driver communicates with both bridges over i2c. The video
> + * signal pipeline is as follows:
> + *
> + * Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
> + *
> + */
> +
> +#include <linux/gpio.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_edid.h>
> +#include <drm/drmP.h>
> +
> +/*
> + * 220Mhz is a limitation of the host, as the bridge is capable of up to
> + * 330Mhz. See section 9.2.1.2.4 of the i.MX 6Dual/6Quad Applications
> + * Processor Reference Manual for more information about the 220Mhz limit.
> + * The imx-ldb driver will warn about clocks over 170Mhz, but it seem to work
> + * fine.
> + */
> +#define MAX_PIXEL_CLOCK 220000
> +
> +#define EDID_EXT_BLOCK_CNT 0x7E
> +
> +#define STDP4028_IRQ_OUT_CONF_REG 0x02
> +#define STDP4028_DPTX_IRQ_EN_REG 0x3C
> +#define STDP4028_DPTX_IRQ_STS_REG 0x3D
> +#define STDP4028_DPTX_STS_REG 0x3E
> +
> +#define STDP4028_DPTX_DP_IRQ_EN 0x1000
> +
> +#define STDP4028_DPTX_HOTPLUG_IRQ_EN 0x0400
> +#define STDP4028_DPTX_LINK_CH_IRQ_EN 0x2000
> +#define STDP4028_DPTX_IRQ_CONFIG \
> + (STDP4028_DPTX_LINK_CH_IRQ_EN | STDP4028_DPTX_HOTPLUG_IRQ_EN)
> +
> +#define STDP4028_DPTX_HOTPLUG_STS 0x0200
> +#define STDP4028_DPTX_LINK_STS 0x1000
> +#define STDP4028_CON_STATE_CONNECTED \
> + (STDP4028_DPTX_HOTPLUG_STS | STDP4028_DPTX_LINK_STS)
> +
> +#define STDP4028_DPTX_HOTPLUG_CH_STS 0x0400
> +#define STDP4028_DPTX_LINK_CH_STS 0x2000
> +#define STDP4028_DPTX_IRQ_CLEAR \
> + (STDP4028_DPTX_LINK_CH_STS | STDP4028_DPTX_HOTPLUG_CH_STS)
> +
> +struct ge_b850v3_lvds_dp {
> + struct drm_connector connector;
> + struct drm_bridge bridge;
> + struct i2c_client *ge_b850v3_lvds_dp_i2c;
> + struct i2c_client *edid_i2c;
> + struct edid *edid;
> + struct mutex lock;
> +};
> +
> +static inline struct ge_b850v3_lvds_dp *
> + bridge_to_ge_b850v3_lvds_dp(struct drm_bridge *bridge)
> +{
> + return container_of(bridge, struct ge_b850v3_lvds_dp, bridge);
> +}
> +
> +static inline struct ge_b850v3_lvds_dp *
> + connector_to_ge_b850v3_lvds_dp(struct drm_connector *connector)
> +{
> + return container_of(connector, struct ge_b850v3_lvds_dp, connector);
> +}
> +
> +u8 *stdp2690_get_edid(struct i2c_client *client)
> +{
> + struct i2c_adapter *adapter = client->adapter;
> + unsigned char start = 0x00;
> + unsigned int total_size;
> + u8 *block = kmalloc(EDID_LENGTH, GFP_KERNEL);
> +
> + struct i2c_msg msgs[] = {
> + {
> + .addr = client->addr,
> + .flags = 0,
> + .len = 1,
> + .buf = &start,
> + }, {
> + .addr = client->addr,
> + .flags = I2C_M_RD,
> + .len = EDID_LENGTH,
> + .buf = block,
> + }
> + };
> +
> + if (!block)
> + return NULL;
> +
> + if (i2c_transfer(adapter, msgs, 2) != 2) {
> + DRM_ERROR("Unable to read EDID.\n");
> + goto err;
> + }
> +
> + if (!drm_edid_block_valid(block, 0, false, NULL)) {
> + DRM_ERROR("Invalid EDID block\n");
> + goto err;
> + }
> +
> + total_size = (block[EDID_EXT_BLOCK_CNT] + 1) * EDID_LENGTH;
> + if (total_size > EDID_LENGTH) {
> + kfree(block);
> + block = kmalloc(total_size, GFP_KERNEL);
> + if (!block)
> + return NULL;
> +
> + /* Yes, read the entire buffer, and do not skip the first
> + * EDID_LENGTH bytes.
> + */
> + start = 0x00;
> + msgs[1].len = total_size;
> + msgs[1].buf = block;
> +
> + if (i2c_transfer(adapter, msgs, 2) != 2) {
> + DRM_ERROR("Unable to read EDID extension blocks.\n");
> + goto err;
> + }
> + }
> +
> + return block;
> +
> +err:
> + kfree(block);
> + return NULL;
> +}
> +
> +static int ge_b850v3_lvds_dp_get_modes(struct drm_connector *connector)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge;
> + struct i2c_client *client;
> + int num_modes = 0;
> +
> + ptn_bridge = connector_to_ge_b850v3_lvds_dp(connector);
> + client = ptn_bridge->edid_i2c;
> +
> + mutex_lock(&ptn_bridge->lock);
> +
> + kfree(ptn_bridge->edid);
> + ptn_bridge->edid = (struct edid *) stdp2690_get_edid(client);
> +
> + if (ptn_bridge->edid) {
> + drm_mode_connector_update_edid_property(connector,
> + ptn_bridge->edid);
> + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
> + }
> +
> + mutex_unlock(&ptn_bridge->lock);
> +
> + return num_modes;
> +}
> +
> +
> +static enum drm_mode_status ge_b850v3_lvds_dp_mode_valid(
> + struct drm_connector *connector, struct drm_display_mode *mode)
> +{
> + if (mode->clock > MAX_PIXEL_CLOCK) {
> + DRM_INFO("The pixel clock for the mode %s is too high, and not supported.",
> + mode->name);
> + return MODE_CLOCK_HIGH;
> + }
> +
> + return MODE_OK;
> +}
> +
> +static const struct
> +drm_connector_helper_funcs ge_b850v3_lvds_dp_connector_helper_funcs = {
> + .get_modes = ge_b850v3_lvds_dp_get_modes,
> + .mode_valid = ge_b850v3_lvds_dp_mode_valid,
> +};
> +
> +static enum drm_connector_status ge_b850v3_lvds_dp_detect(
> + struct drm_connector *connector, bool force)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge =
> + connector_to_ge_b850v3_lvds_dp(connector);
> + struct i2c_client *ge_b850v3_lvds_dp_i2c =
> + ptn_bridge->ge_b850v3_lvds_dp_i2c;
> + s32 link_state;
> +
> + link_state = i2c_smbus_read_word_data(ge_b850v3_lvds_dp_i2c,
> + STDP4028_DPTX_STS_REG);
> +
> + if (link_state == STDP4028_CON_STATE_CONNECTED)
> + return connector_status_connected;
> +
> + if (link_state == 0)
> + return connector_status_disconnected;
> +
> + return connector_status_unknown;
> +}
> +
> +static const struct drm_connector_funcs ge_b850v3_lvds_dp_connector_funcs = {
> + .dpms = drm_atomic_helper_connector_dpms,
> + .fill_modes = drm_helper_probe_single_connector_modes,
> + .detect = ge_b850v3_lvds_dp_detect,
> + .destroy = drm_connector_cleanup,
> + .reset = drm_atomic_helper_connector_reset,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static irqreturn_t ge_b850v3_lvds_dp_irq_handler(int irq, void *dev_id)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge = dev_id;
> + struct i2c_client *ge_b850v3_lvds_dp_i2c
> + = ptn_bridge->ge_b850v3_lvds_dp_i2c;
> +
> + mutex_lock(&ptn_bridge->lock);
> +
> + i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
> + STDP4028_DPTX_IRQ_STS_REG, STDP4028_DPTX_IRQ_CLEAR);
> +
> + mutex_unlock(&ptn_bridge->lock);
> +
> + if (ptn_bridge->connector.dev)
> + drm_kms_helper_hotplug_event(ptn_bridge->connector.dev);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int ge_b850v3_lvds_dp_attach(struct drm_bridge *bridge)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge
> + = bridge_to_ge_b850v3_lvds_dp(bridge);
> + struct drm_connector *connector = &ptn_bridge->connector;
> + struct i2c_client *ge_b850v3_lvds_dp_i2c
> + = ptn_bridge->ge_b850v3_lvds_dp_i2c;
> + int ret;
> +
> + if (!bridge->encoder) {
> + DRM_ERROR("Parent encoder object not found");
> + return -ENODEV;
> + }
> +
> + connector->polled = DRM_CONNECTOR_POLL_HPD;
> +
> + drm_connector_helper_add(connector,
> + &ge_b850v3_lvds_dp_connector_helper_funcs);
> +
> + ret = drm_connector_init(bridge->dev, connector,
> + &ge_b850v3_lvds_dp_connector_funcs,
> + DRM_MODE_CONNECTOR_DisplayPort);
> + if (ret) {
> + DRM_ERROR("Failed to initialize connector with drm\n");
> + return ret;
> + }
> +
> + drm_connector_register(connector);
Connectors shouldn't be registered in the bridge driver, they should
be registered by the kms driver after drm_dev_register is called.
The drm_connector_register_all() API is used for that.
> + ret = drm_mode_connector_attach_encoder(connector, bridge->encoder);
> + if (ret)
> + return ret;
> +
> + drm_bridge_enable(bridge);
This drm_bridge_enable() doesn't seem to serve any purpose here. It also
doesn't seem to make much sense to call drm_bridge_() funcs within a
bridge op itself.
> + if (ge_b850v3_lvds_dp_i2c->irq) {
> + drm_helper_hpd_irq_event(connector->dev);
> +
> + ret = devm_request_threaded_irq(&ge_b850v3_lvds_dp_i2c->dev,
> + ge_b850v3_lvds_dp_i2c->irq, NULL,
> + ge_b850v3_lvds_dp_irq_handler,
> + IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> + "ge-b850v3-lvds-dp", ptn_bridge);
Is there a reason why we register the interrupt handler here and not in
probe?
Thanks,
Archit
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH V5 3/4] drm/bridge: Add driver for GE B850v3 LVDS/DP++ Bridge
From: Archit Taneja @ 2016-09-26 10:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3a56-57e8e300-3-10c8a340@87357206>
Hi,
On 09/26/2016 02:28 PM, Peter Senna Tschudin wrote:
> Hi Archit,
>
> On Monday, September 26, 2016 10:31 CEST, Archit Taneja <architt@codeaurora.org> wrote:
>
>> Hi Peter,
>>
>> On 09/26/2016 01:57 PM, Peter Senna Tschudin wrote:
>>> Patch 1/4 is already on linux-next, but what about this one? Ping?
>
>>
>> I'd posted some queries a couple of times which you didn't answer to.
>> Could you please respond to them before we try to get this merged?
>
> Your queries were already answered by similar questions. The commit messages and cover letter also addresses the design decisions of the code. But basically the driver usefulness to other scenarios is severely limited by the firmware used by both chips. And when using the firmware that goes with this specific hardware, then yes, the two chips are always expected to work together. But the main point is that with the custom firmware each chip do not behave as independent bridges anymore.
Thanks for the reply.
It wasn't entirely clear from the commit message that a custom firmware
was exclusively used on this board to program these chips in order to
get these 2 working together.
I browsed the earlier versions of the patch and saw you explained
the same thing to someone else. Sorry about that, I missed reading
that before.
Could you please specify this explicitly in the commit message? Perhaps,
also mention that there is an external microcontroller with a custom
firmware that manages most of the video operations. For the sake of
completeness, could you also mention the part name of the controller
that's running this firmware?
Also, in the comments in the beginning of the driver:
"However the physical bridges are automatically configured by the input
video signal, and the driver has no access to the video processing
pipeline."
Is the automatic configuration done by the firmware, or is it a
feature of the chips itself?
>
> On the other side, I was careful to use meaningful names for the registers, so a future implementation based on same chips can take the basics from this work, at least as a starting point.
Thanks, that would be handy for later.
I had some comments on the code. I'll share those in another reply.
Archit
>
> Thanks,
>
> Peter
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH][v2] drm/sun4i: rgb: Enable panel after controller
From: Jonathan Liu @ 2016-09-26 10:21 UTC (permalink / raw)
To: linux-arm-kernel
The panel should be enabled after the controller so that we do not have
visual glitches on the panel while the controller is setup. Similarly,
the panel should be disabled before the controller.
Signed-off-by: Jonathan Liu <net147@gmail.com>
---
Changes in v2:
- Changed the commit message to be clearer
drivers/gpu/drm/sun4i/sun4i_rgb.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index c3ff10f..4e4bea6 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -152,15 +152,16 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Enabling RGB output\n");
- if (!IS_ERR(tcon->panel)) {
+ if (!IS_ERR(tcon->panel))
drm_panel_prepare(tcon->panel);
- drm_panel_enable(tcon->panel);
- }
/* encoder->bridge can be NULL; drm_bridge_enable checks for it */
drm_bridge_enable(encoder->bridge);
sun4i_tcon_channel_enable(tcon, 0);
+
+ if (!IS_ERR(tcon->panel))
+ drm_panel_enable(tcon->panel);
}
static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
@@ -171,15 +172,16 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Disabling RGB output\n");
+ if (!IS_ERR(tcon->panel))
+ drm_panel_disable(tcon->panel);
+
sun4i_tcon_channel_disable(tcon, 0);
/* encoder->bridge can be NULL; drm_bridge_disable checks for it */
drm_bridge_disable(encoder->bridge);
- if (!IS_ERR(tcon->panel)) {
- drm_panel_disable(tcon->panel);
+ if (!IS_ERR(tcon->panel))
drm_panel_unprepare(tcon->panel);
- }
}
static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
--
2.10.0
^ permalink raw reply related
* [PATCH 1/2] armv8: aarch32: Execute 32-bit Linux for LayerScape platforms
From: Jason Jin @ 2016-09-26 9:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4642389.nHAzKPNi96@wuerfel>
> Subject: Re: [PATCH 1/2] armv8: aarch32: Execute 32-bit Linux for LayerScape
> platforms
>
> On Friday, September 23, 2016 4:09:29 PM CEST Stuart Yoder wrote:
> > > -----Original Message-----
> > > From: Arnd Bergmann [mailto:arnd at arndb.de]
> > > Sent: Friday, September 23, 2016 10:58 AM
>
> > > > Really, though, the firmware call thing is an incredibly niche use-case.
> > > > Beyond development, the only real benefit of starting an AArch32
> > > > kernel in Hyp is that you can run AArch32 KVM guests, which you
> > > > can do equally well (if not better) under an AArch64 kernel.
> > >
> > > This was my question earlier in the thread, apparently Alison has
> > > another use case in mind, but I don't yet know what that is. If that
> > > use case is important enough, we could do it this way.
> > >
> > > The only use case I can think of at the moment is boot testing on
> > > kernelci.org, which could be used to check whether all the drivers
> > > work in 32-bit environments.
> >
> > The reason we want aarch32 kernel support is for specific customers
> > that have requirements for legacy 32-bit kernel drivers that function
> > on ARMv7 but for some reason are very problematic to port to a 64-bit
> > kernel. So, the way to ease the 64-bit transition is allow them to run an
> aarch32 kernel
> > and their driver on an ARMv8 SoC. I don't think we specifically care
> > whether the kernel starts at EL2 or EL1.
>
> Thanks for the explanation. Unfortunately I don't think that helps get this
> approach upstream, in particular I wouldn't want to add a platform specific
> hack just to help a third party not have to fix their out-of-tree drivers to be 64-
> bit clean.
>
> If your customer already has a chunk of downstream patches large enough to
> be problematic to rebuild for 64-bit, they should be able to also pick up these
> two patches, but of course what we really want is to get drivers upstream and
> fixed (presumably this would be an even larger task than just fixing them, so I
> don't set my hopes too high here).
>
> I'm still not opposed to making *all* 64-bit platforms available to 32-bit kernels
> for testing purposes though, and that would solve the customer problem too,
> as would the approach of encapsulating the kernel in hypervisor stub that
> implements the PSCI calls and using MACH_VIRT with the respective layerscape
> drivers enabled.
>
[Jason] Thanks for all the comments regarding to the ARMv8 32bit kernel patches.
I'd like to provide some comment from this thread.
To run the 32bit kernel on ARMv8, we also provided some patches to u-boot. The
same U-boot image will be used to boot up the 64bit and 32bit kernel. With u-boot
patches, bootm will automatically identify the kernel image, if it's 32bit kernel image,
u-boot will change the ES to AArch32 EL2 and boot up the 32bit kernel. So we do
not need to wrap the 32bit image with 64bit bootup protocol.
Our FW set the u-boot to EL2 and did not have the 'NEW' SMC call to switch the
AArch64(EL2) to AArch32(EL2) at this moment, so this patch set did not rely on
the FW and did not implement the PSCI for secondary core bootup.
I agree with Robin that maybe it's not necessary to support the Hyp for ARMv8 AArch32,
so we can boot up the 32bit kernel with EL1 directly. With this assumption, I think we
can switch to FW and PSCI for SMP easily and drop the spin table patches.
Thanks all for the suggestion. We'll try the "Generic DT based system" instead of
introducing a new platform to support the 32bit kernel. And rely on the dtb built
from ARM64 to bootup the system. Not sure at this moment if some minor update
patches still needed for ARMv8.
Jason
> Arnd
^ permalink raw reply
* [PATCH v8 1/4] soc: mediatek: Refine scpsys to support multiple platform
From: James Liao @ 2016-09-26 9:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <92a5bc68-0c4c-b9e1-17d7-34c83020aa37@gmail.com>
On Wed, 2016-09-21 at 12:25 +0200, Matthias Brugger wrote:
>
> On 19/07/16 09:04, James Liao wrote:
> > Refine scpsys driver common code to support multiple SoC / platform.
> >
> > Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
> > Reviewed-by: Kevin Hilman <khilman@baylibre.com>
> > ---
> > drivers/soc/mediatek/mtk-scpsys.c | 363 +++++++++++++++++++++++---------------
> > 1 file changed, 220 insertions(+), 143 deletions(-)
> >
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index 837effe..1f3555a 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -11,17 +11,15 @@
> > * GNU General Public License for more details.
> > */
> > #include <linux/clk.h>
> > -#include <linux/delay.h>
> > +#include <linux/init.h>
> > #include <linux/io.h>
> > -#include <linux/kernel.h>
> > #include <linux/mfd/syscon.h>
> > -#include <linux/init.h>
> > #include <linux/of_device.h>
> > #include <linux/platform_device.h>
> > #include <linux/pm_domain.h>
> > -#include <linux/regmap.h>
> > -#include <linux/soc/mediatek/infracfg.h>
> > #include <linux/regulator/consumer.h>
> > +#include <linux/soc/mediatek/infracfg.h>
> > +
> > #include <dt-bindings/power/mt8173-power.h>
> >
> > #define SPM_VDE_PWR_CON 0x0210
> > @@ -34,6 +32,7 @@
> > #define SPM_MFG_2D_PWR_CON 0x02c0
> > #define SPM_MFG_ASYNC_PWR_CON 0x02c4
> > #define SPM_USB_PWR_CON 0x02cc
> > +
> > #define SPM_PWR_STATUS 0x060c
> > #define SPM_PWR_STATUS_2ND 0x0610
> >
> > @@ -55,12 +54,12 @@
> > #define PWR_STATUS_USB BIT(25)
> >
> > enum clk_id {
> > - MT8173_CLK_NONE,
> > - MT8173_CLK_MM,
> > - MT8173_CLK_MFG,
> > - MT8173_CLK_VENC,
> > - MT8173_CLK_VENC_LT,
> > - MT8173_CLK_MAX,
> > + CLK_NONE,
> > + CLK_MM,
> > + CLK_MFG,
> > + CLK_VENC,
> > + CLK_VENC_LT,
> > + CLK_MAX,
> > };
> >
> > #define MAX_CLKS 2
> > @@ -76,98 +75,6 @@ struct scp_domain_data {
> > bool active_wakeup;
> > };
> >
> > -static const struct scp_domain_data scp_domain_data[] = {
> > - [MT8173_POWER_DOMAIN_VDEC] = {
> > - .name = "vdec",
> > - .sta_mask = PWR_STATUS_VDEC,
> > - .ctl_offs = SPM_VDE_PWR_CON,
> > - .sram_pdn_bits = GENMASK(11, 8),
> > - .sram_pdn_ack_bits = GENMASK(12, 12),
> > - .clk_id = {MT8173_CLK_MM},
> > - },
> > - [MT8173_POWER_DOMAIN_VENC] = {
> > - .name = "venc",
> > - .sta_mask = PWR_STATUS_VENC,
> > - .ctl_offs = SPM_VEN_PWR_CON,
> > - .sram_pdn_bits = GENMASK(11, 8),
> > - .sram_pdn_ack_bits = GENMASK(15, 12),
> > - .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
> > - },
> > - [MT8173_POWER_DOMAIN_ISP] = {
> > - .name = "isp",
> > - .sta_mask = PWR_STATUS_ISP,
> > - .ctl_offs = SPM_ISP_PWR_CON,
> > - .sram_pdn_bits = GENMASK(11, 8),
> > - .sram_pdn_ack_bits = GENMASK(13, 12),
> > - .clk_id = {MT8173_CLK_MM},
> > - },
> > - [MT8173_POWER_DOMAIN_MM] = {
> > - .name = "mm",
> > - .sta_mask = PWR_STATUS_DISP,
> > - .ctl_offs = SPM_DIS_PWR_CON,
> > - .sram_pdn_bits = GENMASK(11, 8),
> > - .sram_pdn_ack_bits = GENMASK(12, 12),
> > - .clk_id = {MT8173_CLK_MM},
> > - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
> > - MT8173_TOP_AXI_PROT_EN_MM_M1,
> > - },
> > - [MT8173_POWER_DOMAIN_VENC_LT] = {
> > - .name = "venc_lt",
> > - .sta_mask = PWR_STATUS_VENC_LT,
> > - .ctl_offs = SPM_VEN2_PWR_CON,
> > - .sram_pdn_bits = GENMASK(11, 8),
> > - .sram_pdn_ack_bits = GENMASK(15, 12),
> > - .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
> > - },
> > - [MT8173_POWER_DOMAIN_AUDIO] = {
> > - .name = "audio",
> > - .sta_mask = PWR_STATUS_AUDIO,
> > - .ctl_offs = SPM_AUDIO_PWR_CON,
> > - .sram_pdn_bits = GENMASK(11, 8),
> > - .sram_pdn_ack_bits = GENMASK(15, 12),
> > - .clk_id = {MT8173_CLK_NONE},
> > - },
> > - [MT8173_POWER_DOMAIN_USB] = {
> > - .name = "usb",
> > - .sta_mask = PWR_STATUS_USB,
> > - .ctl_offs = SPM_USB_PWR_CON,
> > - .sram_pdn_bits = GENMASK(11, 8),
> > - .sram_pdn_ack_bits = GENMASK(15, 12),
> > - .clk_id = {MT8173_CLK_NONE},
> > - .active_wakeup = true,
> > - },
> > - [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
> > - .name = "mfg_async",
> > - .sta_mask = PWR_STATUS_MFG_ASYNC,
> > - .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
> > - .sram_pdn_bits = GENMASK(11, 8),
> > - .sram_pdn_ack_bits = 0,
> > - .clk_id = {MT8173_CLK_MFG},
> > - },
> > - [MT8173_POWER_DOMAIN_MFG_2D] = {
> > - .name = "mfg_2d",
> > - .sta_mask = PWR_STATUS_MFG_2D,
> > - .ctl_offs = SPM_MFG_2D_PWR_CON,
> > - .sram_pdn_bits = GENMASK(11, 8),
> > - .sram_pdn_ack_bits = GENMASK(13, 12),
> > - .clk_id = {MT8173_CLK_NONE},
> > - },
> > - [MT8173_POWER_DOMAIN_MFG] = {
> > - .name = "mfg",
> > - .sta_mask = PWR_STATUS_MFG,
> > - .ctl_offs = SPM_MFG_PWR_CON,
> > - .sram_pdn_bits = GENMASK(13, 8),
> > - .sram_pdn_ack_bits = GENMASK(21, 16),
> > - .clk_id = {MT8173_CLK_NONE},
> > - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
> > - MT8173_TOP_AXI_PROT_EN_MFG_M0 |
> > - MT8173_TOP_AXI_PROT_EN_MFG_M1 |
> > - MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
> > - },
> > -};
> > -
> > -#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data)
> > -
> > struct scp;
> >
> > struct scp_domain {
> > @@ -179,7 +86,7 @@ struct scp_domain {
> > };
> >
> > struct scp {
> > - struct scp_domain domains[NUM_DOMAINS];
> > + struct scp_domain *domains;
> > struct genpd_onecell_data pd_data;
> > struct device *dev;
> > void __iomem *base;
> > @@ -408,57 +315,69 @@ static bool scpsys_active_wakeup(struct device *dev)
> > return scpd->data->active_wakeup;
> > }
> >
> > -static int scpsys_probe(struct platform_device *pdev)
> > +static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
> > +{
> > + enum clk_id clk_ids[] = {
> > + CLK_MM,
> > + CLK_MFG,
> > + CLK_VENC,
> > + CLK_VENC_LT
> > + };
> > +
> > + static const char * const clk_names[] = {
> > + "mm",
> > + "mfg",
> > + "venc",
> > + "venc_lt",
> > + };
> > +
> > + int i;
> > +
> > + for (i = 0; i < ARRAY_SIZE(clk_ids); i++)
> > + clk[clk_ids[i]] = devm_clk_get(&pdev->dev, clk_names[i]);
>
> Should be:
> for (i = CLK_NONE + 1; i < CLK_MAX; i++)
>
> then we can get rid of clk_ids[].
I'll change it in next patch.
> > +}
> > +
> > +static struct scp *init_scp(struct platform_device *pdev,
> > + const struct scp_domain_data *scp_domain_data, int num)
> > {
> > struct genpd_onecell_data *pd_data;
> > struct resource *res;
> > - int i, j, ret;
> > + int i, j;
> > struct scp *scp;
> > - struct clk *clk[MT8173_CLK_MAX];
> > + struct clk *clk[CLK_MAX];
> >
> > scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
> > if (!scp)
> > - return -ENOMEM;
> > + return ERR_PTR(-ENOMEM);
> >
> > scp->dev = &pdev->dev;
> >
> > res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > scp->base = devm_ioremap_resource(&pdev->dev, res);
> > if (IS_ERR(scp->base))
> > - return PTR_ERR(scp->base);
> > -
> > - pd_data = &scp->pd_data;
> > -
> > - pd_data->domains = devm_kzalloc(&pdev->dev,
> > - sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
> > - if (!pd_data->domains)
> > - return -ENOMEM;
> > -
> > - clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
> > - if (IS_ERR(clk[MT8173_CLK_MM]))
> > - return PTR_ERR(clk[MT8173_CLK_MM]);
> > -
> > - clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
> > - if (IS_ERR(clk[MT8173_CLK_MFG]))
> > - return PTR_ERR(clk[MT8173_CLK_MFG]);
> > -
> > - clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
> > - if (IS_ERR(clk[MT8173_CLK_VENC]))
> > - return PTR_ERR(clk[MT8173_CLK_VENC]);
> > -
> > - clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
> > - if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
> > - return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
> > + return ERR_CAST(scp->base);
> >
> > scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> > "infracfg");
> > if (IS_ERR(scp->infracfg)) {
> > dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
> > PTR_ERR(scp->infracfg));
> > - return PTR_ERR(scp->infracfg);
> > + return ERR_CAST(scp->infracfg);
> > }
> >
> > - for (i = 0; i < NUM_DOMAINS; i++) {
> > + scp->domains = devm_kzalloc(&pdev->dev,
> > + sizeof(*scp->domains) * num, GFP_KERNEL);
> > + if (!scp->domains)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + pd_data = &scp->pd_data;
> > +
> > + pd_data->domains = devm_kzalloc(&pdev->dev,
> > + sizeof(*pd_data->domains) * num, GFP_KERNEL);
> > + if (!pd_data->domains)
> > + return ERR_PTR(-ENOMEM);
> > +
>
> While at it, please leave this block of code between
> devm_ioremap_resource(...) and syscon_regmap_lookup_by_phandle(...)
OK, I'll change it in next patch.
Best regards,
James
^ permalink raw reply
* [PATCH v13 4/4] arm: dts: mt2701: Use real clock for UARTs
From: Erin Lo @ 2016-09-26 9:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474881991-17429-1-git-send-email-erin.lo@mediatek.com>
We used to use a fixed rate clock for the UARTs. Now that we have clock
support we can associate the correct clocks to the UARTs and drop the
26MHz fixed rate UART clock.
Signed-off-by: Erin Lo <erin.lo@mediatek.com>
---
arch/arm/boot/dts/mt2701.dtsi | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index c9a8dbf..7eab6f4 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -73,12 +73,6 @@
#clock-cells = <0>;
};
- uart_clk: dummy26m {
- compatible = "fixed-clock";
- clock-frequency = <26000000>;
- #clock-cells = <0>;
- };
-
clk26m: oscillator at 0 {
compatible = "fixed-clock";
#clock-cells = <0>;
@@ -186,7 +180,8 @@
"mediatek,mt6577-uart";
reg = <0 0x11002000 0 0x400>;
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&uart_clk>;
+ clocks = <&pericfg CLK_PERI_UART0_SEL>, <&pericfg CLK_PERI_UART0>;
+ clock-names = "baud", "bus";
status = "disabled";
};
@@ -195,7 +190,8 @@
"mediatek,mt6577-uart";
reg = <0 0x11003000 0 0x400>;
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&uart_clk>;
+ clocks = <&pericfg CLK_PERI_UART1_SEL>, <&pericfg CLK_PERI_UART1>;
+ clock-names = "baud", "bus";
status = "disabled";
};
@@ -204,7 +200,8 @@
"mediatek,mt6577-uart";
reg = <0 0x11004000 0 0x400>;
interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&uart_clk>;
+ clocks = <&pericfg CLK_PERI_UART2_SEL>, <&pericfg CLK_PERI_UART2>;
+ clock-names = "baud", "bus";
status = "disabled";
};
@@ -213,7 +210,8 @@
"mediatek,mt6577-uart";
reg = <0 0x11005000 0 0x400>;
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&uart_clk>;
+ clocks = <&pericfg CLK_PERI_UART3_SEL>, <&pericfg CLK_PERI_UART3>;
+ clock-names = "baud", "bus";
status = "disabled";
};
};
--
1.9.1
^ permalink raw reply related
* [PATCH v13 3/4] arm: dts: mt2701: Add clock controller device nodes
From: Erin Lo @ 2016-09-26 9:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474881991-17429-1-git-send-email-erin.lo@mediatek.com>
From: James Liao <jamesjj.liao@mediatek.com>
Add clock controller nodes for MT2701, include topckgen, infracfg,
pericfg, apmixedsys, mmsys, imgsys, vdecsys, hifsys, ethsys and
bdpsys. This patch also add two oscillators that provide clocks for
MT2701.
Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
Signed-off-by: Erin Lo <erin.lo@mediatek.com>
---
arch/arm/boot/dts/mt2701.dtsi | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 18596a2..c9a8dbf 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -12,8 +12,10 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/clock/mt2701-clk.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/mt2701-resets.h>
#include "skeleton64.dtsi"
#include "mt2701-pinfunc.h"
@@ -77,6 +79,20 @@
#clock-cells = <0>;
};
+ clk26m: oscillator at 0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <26000000>;
+ clock-output-names = "clk26m";
+ };
+
+ rtc32k: oscillator at 1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32000>;
+ clock-output-names = "rtc32k";
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupt-parent = <&gic>;
@@ -104,6 +120,26 @@
reg = <0 0x10005000 0 0x1000>;
};
+ topckgen: syscon at 10000000 {
+ compatible = "mediatek,mt2701-topckgen", "syscon";
+ reg = <0 0x10000000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ infracfg: syscon at 10001000 {
+ compatible = "mediatek,mt2701-infracfg", "syscon";
+ reg = <0 0x10001000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ pericfg: syscon at 10003000 {
+ compatible = "mediatek,mt2701-pericfg", "syscon";
+ reg = <0 0x10003000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
watchdog: watchdog at 10007000 {
compatible = "mediatek,mt2701-wdt",
"mediatek,mt6589-wdt";
@@ -128,6 +164,12 @@
reg = <0 0x10200100 0 0x1c>;
};
+ apmixedsys: syscon at 10209000 {
+ compatible = "mediatek,mt2701-apmixedsys", "syscon";
+ reg = <0 0x10209000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
gic: interrupt-controller at 10211000 {
compatible = "arm,cortex-a7-gic";
interrupt-controller;
--
1.9.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