Linux Serial subsystem development
 help / color / mirror / Atom feed
* Re: [PATCH v2 21/24] rave-sp: Support for variants on modalias drivers
From: Ricardo Ribalda Delgado @ 2018-06-11 15:21 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Andy Shevchenko, LKML, open list:SERIAL DRIVERS, Lee Jones,
	Rob Herring, Johan Hovold
In-Reply-To: <8912BE88-4AA3-44ED-9828-57666CB31522@holtmann.org>

Hello


On Mon, Jun 11, 2018 at 3:38 PM Marcel Holtmann <marcel@holtmann.org> wrote:
>
> Hi Andy,
>
> >> Rave-sp behaves differently based on the device variant.
> >
> >
> >>        sp->variant = of_device_get_match_data(dev);
> >> +       if (!sp->variant) {
> >> +               id = serdev_match_id(rave_sp_serdev_id, serdev);
> >
> > I think you may leave the ID table where it is in the code and use link.
> >
> >> +               if (id)
> >> +                       sp->variant = (const struct rave_sp_variant *)
> >> +                                                       id->driver_data;
> >> +       }
> >
> > Perhaps a helper like it's done for ACPI / OF cases?
> >
> > [device_get_match_data() -> ]
> >  of_fwnode_device_get_match_data()
> >  acpi_fwnode_device_get_match_data()
>
> something like that and frankly this is trying to hard. This driver is currently really DT specific and can be fixed up later. It is causing a lot of noise in this patch series. I would really urge to focus on the core changes get prominent drivers support. I think hci_bcm.c is a good example since a) we need to fix up Edison and b) new ACPI based tablets might be able to allow for easy testing.

I can try to implement something like andy proposes, but if it turns
out too complicated we can remove this driver from the series.

Thanks!

>
> Regards
>
> Marcel
>


-- 
Ricardo Ribalda

^ permalink raw reply

* Re: [PATCH v2 15/24] net: qualcomm: MODULE_DEVICE_TABLE(serdev)
From: Marcel Holtmann @ 2018-06-11 15:28 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: LKML, open list:SERIAL DRIVERS, Lino Sanfilippo, David S. Miller,
	Stefan Wahren, Rob Herring, Johan Hovold, netdev
In-Reply-To: <CAPybu_0=ykAcCx=nZyrv90YRfihDxi3s2+Nz+6UP8Fwd5eH2-A@mail.gmail.com>

Hi Marcel,

>> the commit message is misleading me. If I build something with ACPI or DT support, then modinfo will show all modalias information for ACPI and DT compatible strings. What else does udev/modprobe actually need? Is something broken with the modalias export?
> 
> The main purpose is to autoload drivers for devices that have been
> created via sysfs or another module.
> 
> Eg1: We have a serial port on a standard computer that has connected a
> GPS module. Since it is something that is not in the ACPI nor the DT
> table the user will run
> 
> echo serdev_gps > /sys/bus/serial/devices/serial0/new_device
> 
> Eg2 module: https://github.com/ribalda/linux/blob/415bb3f0076c2b846ebe5409589b8e1e3004f55a/drivers/tty/serdev/test_platform.c
> 
> Modprobe does not know what module to load for that device unless
> there is a matching MODULE_DEVICE_TABLE
> Today, we have the same functionality for i2c devices
> https://www.kernel.org/doc/Documentation/i2c/instantiating-devices

but why does this have to be the driver name? I would rather say, create a generic string that describes the hardware and then use that. I think you also want the special handling, as from USB for example, that lets you reference an existing .compatible or ACPI ID as reference so that the driver_data is copied.

Regards

Marcel

^ permalink raw reply

* Re: [PATCH v2 15/24] net: qualcomm: MODULE_DEVICE_TABLE(serdev)
From: Ricardo Ribalda Delgado @ 2018-06-11 15:33 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: LKML, open list:SERIAL DRIVERS, Lino Sanfilippo, David Miller,
	Stefan Wahren, Rob Herring, Johan Hovold, netdev
In-Reply-To: <B4BC9DB0-2D7C-4F9D-99FE-8227D4DC3D54@holtmann.org>

Hi Marcel,
On Mon, Jun 11, 2018 at 5:28 PM Marcel Holtmann <marcel@holtmann.org> wrote:
>
> Hi Marcel,
>
> >> the commit message is misleading me. If I build something with ACPI or DT support, then modinfo will show all modalias information for ACPI and DT compatible strings. What else does udev/modprobe actually need? Is something broken with the modalias export?
> >
> > The main purpose is to autoload drivers for devices that have been
> > created via sysfs or another module.
> >
> > Eg1: We have a serial port on a standard computer that has connected a
> > GPS module. Since it is something that is not in the ACPI nor the DT
> > table the user will run
> >
> > echo serdev_gps > /sys/bus/serial/devices/serial0/new_device
> >
> > Eg2 module: https://github.com/ribalda/linux/blob/415bb3f0076c2b846ebe5409589b8e1e3004f55a/drivers/tty/serdev/test_platform.c
> >
> > Modprobe does not know what module to load for that device unless
> > there is a matching MODULE_DEVICE_TABLE
> > Today, we have the same functionality for i2c devices
> > https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
>
> but why does this have to be the driver name? I would rather say, create a generic string that describes the hardware and then use that. I think you also want the special handling, as from USB for example, that lets you reference an existing .compatible or ACPI ID as reference so that the driver_data is copied.

We can choose any name, but if there are no special variants (like the
rave-sp driver) I would prefer using the module name. We can of course
use more names, like the part number of the the device, but it is very
convenient to also use the module name, and other subsystems also do
that.

If you want to add specific names for this device please let me know
and I will add them to the list. You know much more about this module
than myself.

Thanks!

>
> Regards
>
> Marcel
>


-- 
Ricardo Ribalda

^ permalink raw reply

* Re: [PATCH v6 3/6] mfd: at91-usart: added mfd driver for usart
From: Alexandre Belloni @ 2018-06-11 15:36 UTC (permalink / raw)
  To: Radu Pirea
  Cc: broonie, nicolas.ferre, lee.jones, richard.genoud, robh+dt,
	mark.rutland, gregkh, linux-spi, linux-arm-kernel, linux-kernel,
	devicetree, linux-serial
In-Reply-To: <20180607110020.20565-4-radu.pirea@microchip.com>

On 07/06/2018 14:00:17+0300, Radu Pirea wrote:
> +static int at91_usart_mode_probe(struct platform_device *pdev)
> +{
> +	struct mfd_cell cell;
> +	u32 opmode;

This has to be initialized to AT91_USART_MODE_SERIAL...

> +	int err;
> +
> +	err = device_property_read_u32(&pdev->dev, "atmel,usart-mode", &opmode);
> +

because if the property is not present, then opmode will not be modified
which means it could hold the value of AT91_USART_MODE_SPI.


-- 
Alexandre Belloni, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply

* Re: [PATCH v6 2/6] dt-bindings: add binding for atmel-usart in SPI mode
From: Alexandre Belloni @ 2018-06-11 15:37 UTC (permalink / raw)
  To: Radu Pirea
  Cc: broonie, nicolas.ferre, lee.jones, richard.genoud, robh+dt,
	mark.rutland, gregkh, linux-spi, linux-arm-kernel, linux-kernel,
	devicetree, linux-serial
In-Reply-To: <20180607110020.20565-3-radu.pirea@microchip.com>

Hi,

On 07/06/2018 14:00:16+0300, Radu Pirea wrote:
> diff --git a/include/dt-bindings/mfd/at91-usart.h b/include/dt-bindings/mfd/at91-usart.h
> new file mode 100644
> index 000000000000..ac811628a42d
> --- /dev/null
> +++ b/include/dt-bindings/mfd/at91-usart.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * This header provides macros for AT91 USART DT bindings.
> + *
> + * Copyright (C) 2018 Microchip Technology
> + *
> + * Author: Radu Pirea <radu.pirea@microchip.com>
> + *
> + */
> +
> +#ifndef __DT_BINDINGS_AT91_USART_H__
> +#define __DT_BINDINGS_AT91_USART_H__
> +
> +#define AT91_USART_MODE_SERIAL	1
> +#define AT91_USART_MODE_SPI	2
> +

Nitpick, I'd make that 0 and 1 instead of 1 and 2. That would feel more
natural to me regarding the default value.


-- 
Alexandre Belloni, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply

* Re: [PATCH v2 15/24] net: qualcomm: MODULE_DEVICE_TABLE(serdev)
From: Marcel Holtmann @ 2018-06-11 15:52 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: LKML, open list:SERIAL DRIVERS, Lino Sanfilippo, David S. Miller,
	Stefan Wahren, Rob Herring, Johan Hovold, netdev
In-Reply-To: <CAPybu_2ViGvN6egz-Ajq4+1fv6VAVFswuvSPAVmYH0a9R-Yjvw@mail.gmail.com>

Hi Ricardo,

>>>> the commit message is misleading me. If I build something with ACPI or DT support, then modinfo will show all modalias information for ACPI and DT compatible strings. What else does udev/modprobe actually need? Is something broken with the modalias export?
>>> 
>>> The main purpose is to autoload drivers for devices that have been
>>> created via sysfs or another module.
>>> 
>>> Eg1: We have a serial port on a standard computer that has connected a
>>> GPS module. Since it is something that is not in the ACPI nor the DT
>>> table the user will run
>>> 
>>> echo serdev_gps > /sys/bus/serial/devices/serial0/new_device
>>> 
>>> Eg2 module: https://github.com/ribalda/linux/blob/415bb3f0076c2b846ebe5409589b8e1e3004f55a/drivers/tty/serdev/test_platform.c
>>> 
>>> Modprobe does not know what module to load for that device unless
>>> there is a matching MODULE_DEVICE_TABLE
>>> Today, we have the same functionality for i2c devices
>>> https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
>> 
>> but why does this have to be the driver name? I would rather say, create a generic string that describes the hardware and then use that. I think you also want the special handling, as from USB for example, that lets you reference an existing .compatible or ACPI ID as reference so that the driver_data is copied.
> 
> We can choose any name, but if there are no special variants (like the
> rave-sp driver) I would prefer using the module name. We can of course
> use more names, like the part number of the the device, but it is very
> convenient to also use the module name, and other subsystems also do
> that.
> 
> If you want to add specific names for this device please let me know
> and I will add them to the list. You know much more about this module
> than myself.

if we want to use the driver name, then why not build this into the new_device handling itself instead of duplicating that name in each serdev_device_id table. What is the reference here? For example platform device do matching on driver name if I recall this correctly.

However what is most important is that device_get_match_data() actually works. There should be no difference between DT, ACPI or a dynamic device.

Regards

Marcel

^ permalink raw reply

* Re: [PATCH v2 15/24] net: qualcomm: MODULE_DEVICE_TABLE(serdev)
From: Ricardo Ribalda Delgado @ 2018-06-11 16:21 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: LKML, open list:SERIAL DRIVERS, Lino Sanfilippo, David Miller,
	Stefan Wahren, Rob Herring, Johan Hovold, netdev
In-Reply-To: <07871EF5-D1D3-4677-8100-B5E7F14DB302@holtmann.org>

Hi Marcel,
On Mon, Jun 11, 2018 at 5:52 PM Marcel Holtmann <marcel@holtmann.org> wrote:
>
> Hi Ricardo,
>
> >>>> the commit message is misleading me. If I build something with ACPI or DT support, then modinfo will show all modalias information for ACPI and DT compatible strings. What else does udev/modprobe actually need? Is something broken with the modalias export?
> >>>
> >>> The main purpose is to autoload drivers for devices that have been
> >>> created via sysfs or another module.
> >>>
> >>> Eg1: We have a serial port on a standard computer that has connected a
> >>> GPS module. Since it is something that is not in the ACPI nor the DT
> >>> table the user will run
> >>>
> >>> echo serdev_gps > /sys/bus/serial/devices/serial0/new_device
> >>>
> >>> Eg2 module: https://github.com/ribalda/linux/blob/415bb3f0076c2b846ebe5409589b8e1e3004f55a/drivers/tty/serdev/test_platform.c
> >>>
> >>> Modprobe does not know what module to load for that device unless
> >>> there is a matching MODULE_DEVICE_TABLE
> >>> Today, we have the same functionality for i2c devices
> >>> https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
> >>
> >> but why does this have to be the driver name? I would rather say, create a generic string that describes the hardware and then use that. I think you also want the special handling, as from USB for example, that lets you reference an existing .compatible or ACPI ID as reference so that the driver_data is copied.
> >
> > We can choose any name, but if there are no special variants (like the
> > rave-sp driver) I would prefer using the module name. We can of course
> > use more names, like the part number of the the device, but it is very
> > convenient to also use the module name, and other subsystems also do
> > that.
> >
> > If you want to add specific names for this device please let me know
> > and I will add them to the list. You know much more about this module
> > than myself.
>
> if we want to use the driver name, then why not build this into the new_device handling itself instead of duplicating that name in each serdev_device_id table. What is the reference here? For example platform device do matching on driver name if I recall this correctly.

We do the matching also over driver name at serdev_device_match():

if (sdrv->id_table)
return !!serdev_match_id(sdrv->id_table, sdev);

return strcmp(sdev->modalias, drv->name) == 0;

This is just for the module autoloading

>
> However what is most important is that device_get_match_data() actually works. There should be no difference between DT, ACPI or a dynamic device.

Agree, will take a look to this tomorrow morning.

>
> Regards
>
> Marcel
>


-- 
Ricardo Ribalda

^ permalink raw reply

* [PATCH] serial: pxa: Fix an error handling path in 'serial_pxa_probe()'
From: Christophe JAILLET @ 2018-06-11 17:30 UTC (permalink / raw)
  To: gregkh, jslaby
  Cc: linux-serial, linux-kernel, kernel-janitors, Christophe JAILLET

If port.line is out of range, we still need to release some resources, or
we will leak them.

Fixes: afc7851fab83 ("serial: pxa: Fix out-of-bounds access through serial port index")
Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
---
 drivers/tty/serial/pxa.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index eda3c7710d6a..4932b674f7ef 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -887,7 +887,8 @@ static int serial_pxa_probe(struct platform_device *dev)
 		goto err_clk;
 	if (sport->port.line >= ARRAY_SIZE(serial_pxa_ports)) {
 		dev_err(&dev->dev, "serial%d out of range\n", sport->port.line);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_clk;
 	}
 	snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
 
-- 
2.17.0

^ permalink raw reply related

* Re: [PATCH] serial: 8250_dw: 8250_dw need to depend on COMMON_CLK
From: Andy Shevchenko @ 2018-06-11 21:02 UTC (permalink / raw)
  To: Corentin Labbe
  Cc: Greg Kroah-Hartman, Jiri Slaby, Linux Kernel Mailing List,
	open list:SERIAL DRIVERS
In-Reply-To: <1528310824-12706-1-git-send-email-clabbe@baylibre.com>

On Wed, Jun 6, 2018 at 10:27 PM Corentin Labbe <clabbe@baylibre.com> wrote:
>
> This patch fix the following build error on M68K:
> drivers/tty/serial/8250/8250_dw.o: In function `dw8250_set_termios':
> 8250_dw.c:(.text+0x50c): undefined reference to `clk_round_rate'
> 8250_dw.c:(.text+0x594): undefined reference to `clk_set_rate'
>
> So 8250_dw need to depend on COMMON_CLK.
>

Makes sense.
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
> ---
>  drivers/tty/serial/8250/Kconfig | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
> index f005eaf8bc57..37d4ec5f3cc9 100644
> --- a/drivers/tty/serial/8250/Kconfig
> +++ b/drivers/tty/serial/8250/Kconfig
> @@ -351,7 +351,7 @@ config SERIAL_8250_FSL
>
>  config SERIAL_8250_DW
>         tristate "Support for Synopsys DesignWare 8250 quirks"
> -       depends on SERIAL_8250
> +       depends on SERIAL_8250 && COMMON_CLK
>         help
>           Selecting this option will enable handling of the extra features
>           present in the Synopsys DesignWare APB UART.
> --
> 2.16.4
>


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* [PATCH] drivers/tty: add error handling for pcmcia_loop_config
From: Zhouyang Jia @ 2018-06-12  4:36 UTC (permalink / raw)
  Cc: Zhouyang Jia, Greg Kroah-Hartman, Jiri Slaby, linux-serial,
	linux-kernel

When pcmcia_loop_config fails, the lack of error-handling code may
cause unexpected results.

This patch adds error-handling code after calling pcmcia_loop_config.

Signed-off-by: Zhouyang Jia <jiazhouyang09@gmail.com>
---
 drivers/tty/serial/8250/serial_cs.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 9963a76..c8186a0 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -638,8 +638,10 @@ static int serial_config(struct pcmcia_device *link)
 	    (link->has_func_id) &&
 	    (link->socket->pcmcia_pfc == 0) &&
 	    ((link->func_id == CISTPL_FUNCID_MULTI) ||
-	     (link->func_id == CISTPL_FUNCID_SERIAL)))
-		pcmcia_loop_config(link, serial_check_for_multi, info);
+	     (link->func_id == CISTPL_FUNCID_SERIAL))) {
+		if (pcmcia_loop_config(link, serial_check_for_multi, info))
+			goto failed;
+	}
 
 	/*
 	 * Apply any multi-port quirk.
-- 
2.7.4

^ permalink raw reply related

* [PATCH] tty: serial: add error handling for try_module_get
From: Zhouyang Jia @ 2018-06-12  4:50 UTC (permalink / raw)
  Cc: Zhouyang Jia, Jason Wessel, Daniel Thompson, Greg Kroah-Hartman,
	Jiri Slaby, kgdb-bugreport, linux-serial, linux-kernel

When try_module_get fails, the lack of error-handling code may
cause unexpected results.

This patch adds error-handling code after calling try_module_get.

Signed-off-by: Zhouyang Jia <jiazhouyang09@gmail.com>
---
 drivers/tty/serial/kgdboc.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index b4ba2b1..641e22a 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -286,8 +286,10 @@ static void kgdboc_pre_exp_handler(void)
 		con_debug_enter(vc_cons[fg_console].d);
 	}
 	/* Increment the module count when the debugger is active */
-	if (!kgdb_connected)
-		try_module_get(THIS_MODULE);
+	if (!kgdb_connected) {
+		if (!try_module_get(THIS_MODULE))
+			printk(KERN_ERR "kgdboc: cannot get module.\n");
+	}
 }
 
 static void kgdboc_post_exp_handler(void)
-- 
2.7.4

^ permalink raw reply related

* [PATCH 0/7] MIPS: intel: add initial support for Intel MIPS SoCs
From: Songjun Wu @ 2018-06-12  5:40 UTC (permalink / raw)
  To: hua.ma, yixin.zhu, chuanhua.lei
  Cc: linux-mips, qi-ming.wu, linux-clk, linux-serial, devicetree,
	Songjun Wu, Michael Turquette, James Hogan, Stephen Boyd,
	Jiri Slaby, linux-kernel, Thomas Gleixner, Philippe Ombredanne,
	Rob Herring, Kate Stewart, Greg Kroah-Hartman, Mark Rutland,
	Ralf Baechle

This patch series is for adding the support for Intel MIPS interAptiv SoC GRX500 family.
It includes CCF support, serial driver optimization and DTS modification.

This patch series is applied on top of v4.17.1. Basic verification is performed on GRX500 board.
Any comments on this would be appreciated.

We propose merging this patch series into MIPS Linux tree.


Hua Ma (1):
  MIPS: intel: Add initial support for Intel MIPS SoCs

Songjun Wu (5):
  MIPS: dts: Add aliases node for lantiq danube serial
  tty: serial: lantiq: Always use readl()/writel()
  tty: serial: lantiq: Convert global lock to per device lock
  tty: serial: lantiq: Remove unneeded header includes and macros
  tty: serial: lantiq: Add CCF support

Yixin Zhu (1):
  clk: intel: Add clock driver for GRX500 SoC

 .../devicetree/bindings/clock/intel,grx500-clk.txt |  46 ++
 .../devicetree/bindings/serial/lantiq_asc.txt      |  15 +
 arch/mips/Kbuild.platforms                         |   1 +
 arch/mips/Kconfig                                  |  37 +-
 arch/mips/boot/dts/Makefile                        |   1 +
 arch/mips/boot/dts/intel-mips/Makefile             |   3 +
 arch/mips/boot/dts/intel-mips/easy350_anywan.dts   |  20 +
 arch/mips/boot/dts/intel-mips/xrx500.dtsi          | 196 ++++++
 arch/mips/boot/dts/lantiq/danube.dtsi              |   6 +-
 arch/mips/configs/grx500_defconfig                 | 165 +++++
 .../asm/mach-intel-mips/cpu-feature-overrides.h    |  61 ++
 arch/mips/include/asm/mach-intel-mips/ioremap.h    |  39 ++
 arch/mips/include/asm/mach-intel-mips/irq.h        |  17 +
 .../asm/mach-intel-mips/kernel-entry-init.h        |  76 +++
 arch/mips/include/asm/mach-intel-mips/spaces.h     |  29 +
 arch/mips/include/asm/mach-intel-mips/war.h        |  18 +
 arch/mips/intel-mips/Kconfig                       |  22 +
 arch/mips/intel-mips/Makefile                      |   3 +
 arch/mips/intel-mips/Platform                      |  11 +
 arch/mips/intel-mips/irq.c                         |  36 ++
 arch/mips/intel-mips/prom.c                        | 184 ++++++
 arch/mips/intel-mips/time.c                        |  56 ++
 drivers/clk/Kconfig                                |   1 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/intel/Kconfig                          |  21 +
 drivers/clk/intel/Makefile                         |   7 +
 drivers/clk/intel/clk-cgu-api.c                    | 676 +++++++++++++++++++++
 drivers/clk/intel/clk-cgu-api.h                    | 120 ++++
 drivers/clk/intel/clk-grx500.c                     | 236 +++++++
 drivers/tty/serial/Kconfig                         |   2 +-
 drivers/tty/serial/lantiq.c                        | 415 ++++++++-----
 include/dt-bindings/clock/intel,grx500-clk.h       |  61 ++
 32 files changed, 2418 insertions(+), 164 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/intel,grx500-clk.txt
 create mode 100644 arch/mips/boot/dts/intel-mips/Makefile
 create mode 100644 arch/mips/boot/dts/intel-mips/easy350_anywan.dts
 create mode 100644 arch/mips/boot/dts/intel-mips/xrx500.dtsi
 create mode 100644 arch/mips/configs/grx500_defconfig
 create mode 100644 arch/mips/include/asm/mach-intel-mips/cpu-feature-overrides.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/ioremap.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/irq.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/kernel-entry-init.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/spaces.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/war.h
 create mode 100644 arch/mips/intel-mips/Kconfig
 create mode 100644 arch/mips/intel-mips/Makefile
 create mode 100644 arch/mips/intel-mips/Platform
 create mode 100644 arch/mips/intel-mips/irq.c
 create mode 100644 arch/mips/intel-mips/prom.c
 create mode 100644 arch/mips/intel-mips/time.c
 create mode 100644 drivers/clk/intel/Kconfig
 create mode 100644 drivers/clk/intel/Makefile
 create mode 100644 drivers/clk/intel/clk-cgu-api.c
 create mode 100644 drivers/clk/intel/clk-cgu-api.h
 create mode 100644 drivers/clk/intel/clk-grx500.c
 create mode 100644 include/dt-bindings/clock/intel,grx500-clk.h

-- 
2.11.0

^ permalink raw reply

* [PATCH 1/7] MIPS: dts: Add aliases node for lantiq danube serial
From: Songjun Wu @ 2018-06-12  5:40 UTC (permalink / raw)
  To: hua.ma, yixin.zhu, chuanhua.lei
  Cc: linux-mips, qi-ming.wu, linux-clk, linux-serial, devicetree,
	Songjun Wu, James Hogan, linux-kernel, Thomas Gleixner,
	Philippe Ombredanne, Rob Herring, Kate Stewart,
	Greg Kroah-Hartman, Mark Rutland, Ralf Baechle
In-Reply-To: <20180612054034.4969-1-songjun.wu@linux.intel.com>

Previous implementation uses a hard-coded register value to check if
the current serial entity is the console entity.
Now the lantiq serial driver uses the aliases for the index of the
serial port.
The lantiq danube serial dts are updated with aliases to support this.

Signed-off-by: Songjun Wu <songjun.wu@linux.intel.com>
---

 arch/mips/boot/dts/lantiq/danube.dtsi | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/mips/boot/dts/lantiq/danube.dtsi b/arch/mips/boot/dts/lantiq/danube.dtsi
index 2dd950181f8a..7a9e15da6bd0 100644
--- a/arch/mips/boot/dts/lantiq/danube.dtsi
+++ b/arch/mips/boot/dts/lantiq/danube.dtsi
@@ -4,6 +4,10 @@
 	#size-cells = <1>;
 	compatible = "lantiq,xway", "lantiq,danube";
 
+	aliases {
+		serial0 = &asc1;
+	};
+
 	cpus {
 		cpu@0 {
 			compatible = "mips,mips24Kc";
@@ -74,7 +78,7 @@
 			reg = <0xE100A00 0x100>;
 		};
 
-		serial@E100C00 {
+		asc1: serial@E100C00 {
 			compatible = "lantiq,asc";
 			reg = <0xE100C00 0x400>;
 			interrupt-parent = <&icu0>;
-- 
2.11.0

^ permalink raw reply related

* [PATCH 2/7] clk: intel: Add clock driver for GRX500 SoC
From: Songjun Wu @ 2018-06-12  5:40 UTC (permalink / raw)
  To: hua.ma, yixin.zhu, chuanhua.lei
  Cc: linux-mips, qi-ming.wu, linux-clk, linux-serial, devicetree,
	Songjun Wu, Michael Turquette, Stephen Boyd, linux-kernel,
	Rob Herring, Mark Rutland
In-Reply-To: <20180612054034.4969-1-songjun.wu@linux.intel.com>

From: Yixin Zhu <yixin.zhu@linux.intel.com>

PLL of GRX500 provide clock to DDR, CPU, and peripherals as show below

                 +---------+
	    |--->| LCPLL3 0|--PCIe clk-->
   XO       |    +---------+
+-----------|
            |    +---------+
            |    |        3|--PAE clk-->
            |--->| PLL0B  2|--GSWIP clk-->
            |    |        1|--DDR clk-->DDR PHY clk-->
            |    |        0|--CPU1 clk--+   +-----+
            |    +---------+            |--->0    |
            |                               | MUX |--CPU clk-->
            |    +---------+            |--->1    |
            |    |        0|--CPU0 clk--+   +-----+
            |--->| PLLOA  1|--SSX4 clk-->
                 |        2|--NGI clk-->
                 |        3|--CBM clk-->
                 +---------+

VCO of all PLLs of GRX500 is not supposed to be reprogrammed.
DDR PHY clock is created to show correct clock rate in software
point of view.
CPU clock of 1Ghz from PLL0B otherwise from PLL0A.
Signed-off-by: Yixin Zhu <yixin.zhu@linux.intel.com>

Signed-off-by: Songjun Wu <songjun.wu@linux.intel.com>
---

 .../devicetree/bindings/clock/intel,grx500-clk.txt |  46 ++
 drivers/clk/Kconfig                                |   1 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/intel/Kconfig                          |  21 +
 drivers/clk/intel/Makefile                         |   7 +
 drivers/clk/intel/clk-cgu-api.c                    | 676 +++++++++++++++++++++
 drivers/clk/intel/clk-cgu-api.h                    | 120 ++++
 drivers/clk/intel/clk-grx500.c                     | 236 +++++++
 include/dt-bindings/clock/intel,grx500-clk.h       |  61 ++
 9 files changed, 1169 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/intel,grx500-clk.txt
 create mode 100644 drivers/clk/intel/Kconfig
 create mode 100644 drivers/clk/intel/Makefile
 create mode 100644 drivers/clk/intel/clk-cgu-api.c
 create mode 100644 drivers/clk/intel/clk-cgu-api.h
 create mode 100644 drivers/clk/intel/clk-grx500.c
 create mode 100644 include/dt-bindings/clock/intel,grx500-clk.h

diff --git a/Documentation/devicetree/bindings/clock/intel,grx500-clk.txt b/Documentation/devicetree/bindings/clock/intel,grx500-clk.txt
new file mode 100644
index 000000000000..dd761d900dc9
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/intel,grx500-clk.txt
@@ -0,0 +1,46 @@
+Device Tree Clock bindings for GRX500 PLL controller.
+
+This binding uses the common clock binding:
+	Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+This GRX500 PLL controller provides the 5 main clock domain of the SoC: CPU/DDR, XBAR,
+Voice, WLAN, PCIe and gate clocks for HW modules.
+
+Required properties for osc clock node
+- compatible: Should be intel,grx500-xxx-clk
+- reg: offset address of the controller memory area.
+- clocks: phandle of the external reference clock
+- #clock-cells: can be one or zero.
+- clock-output-names: Names of the output clocks.
+
+Example:
+	pll0aclk: pll0aclk {
+		#clock-cells = <1>;
+		compatible = "intel,grx500-pll0a-clk";
+		clocks = <&pll0a>;
+		reg = <0x8>;
+		clock-output-names = "cbmclk", "ngiclk", "ssx4clk", "cpu0clk";
+	};
+
+	cpuclk: cpuclk {
+		#clock-cells = <0>;
+		compatible = "intel,grx500-cpu-clk";
+		clocks = <&pll0aclk CPU0_CLK>, <&pll0bclk CPU1_CLK>;
+		reg = <0x8>;
+		clock-output-names = "cpu";
+	};
+
+Required properties for gate node:
+- compatible: Should be intel,grx500-gatex-clk
+- reg: offset address of the controller memory area.
+- #clock-cells: Should be <1>
+- clock-output-names: Names of the output clocks.
+
+Example:
+	clkgate0: clkgate0 {
+		#clock-cells = <1>;
+		compatible = "intel,grx500-gate0-clk";
+		reg = <0x114>;
+		clock-output-names = "gate_xbar0", "gate_xbar1", "gate_xbar2",
+		"gate_xbar3", "gate_xbar6", "gate_xbar7";
+	};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 34968a381d0f..9e2e19a1170a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -280,6 +280,7 @@ config COMMON_CLK_STM32H7
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
 source "drivers/clk/imgtec/Kconfig"
+source "drivers/clk/intel/Kconfig"
 source "drivers/clk/keystone/Kconfig"
 source "drivers/clk/mediatek/Kconfig"
 source "drivers/clk/meson/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index de6d06ac790b..ef3e270005a1 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -105,3 +105,4 @@ obj-$(CONFIG_X86)			+= x86/
 endif
 obj-$(CONFIG_ARCH_ZX)			+= zte/
 obj-$(CONFIG_ARCH_ZYNQ)			+= zynq/
+obj-$(CONFIG_COMMON_CLK_INTEL)		+= intel/
diff --git a/drivers/clk/intel/Kconfig b/drivers/clk/intel/Kconfig
new file mode 100644
index 000000000000..d40a92ae7462
--- /dev/null
+++ b/drivers/clk/intel/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0
+config COMMON_CLK_INTEL
+	depends on COMMON_CLK
+	depends on INTEL_MIPS || COMPILE_TEST
+	select MFD_SYSCON
+	bool "Intel clock controller support"
+	help
+	  This driver support Intel GRX500 crystal oscillator clock
+	  using common clock framework.
+
+choice
+	prompt "SoC platform selection"
+	depends on COMMON_CLK_INTEL
+	default INTEL_GRX500_CLK
+
+config INTEL_GRX500_CLK
+	bool "GRX500 CLK"
+	help
+	  Clock driver of GRX500 platform.
+
+endchoice
diff --git a/drivers/clk/intel/Makefile b/drivers/clk/intel/Makefile
new file mode 100644
index 000000000000..1eaa37f797ea
--- /dev/null
+++ b/drivers/clk/intel/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for intel specific clk
+
+obj-y += clk-cgu-api.o
+ifneq ($(CONFIG_INTEL_GRX500_CLK),)
+	obj-y += clk-grx500.o
+endif
diff --git a/drivers/clk/intel/clk-cgu-api.c b/drivers/clk/intel/clk-cgu-api.c
new file mode 100644
index 000000000000..ab0590cb8b60
--- /dev/null
+++ b/drivers/clk/intel/clk-cgu-api.c
@@ -0,0 +1,676 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2016 Intel Corporation.
+ *  Zhu YiXin <Yixin.zhu@intel.com>
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include "clk-cgu-api.h"
+
+#define to_gate_clk(_hw) container_of(_hw, struct gate_clk, hw)
+#define to_clk_gate_dummy(_hw) container_of(_hw, struct gate_dummy_clk, hw)
+#define to_div_clk(_hw) container_of(_hw, struct div_clk, hw)
+#define to_mux_clk(_hw) container_of(_hw, struct mux_clk, hw)
+
+static void set_clk_val(struct regmap *map, u32 reg, u8 shift,
+			u8 width, u32 set_val)
+{
+	u32 mask = GENMASK(width + shift, shift);
+
+	regmap_update_bits(map, reg, mask,
+			   (set_val << shift));
+}
+
+static u32 get_clk_val(struct regmap *map, u32 reg, u8 shift,
+		       u8 width)
+{
+	u32 val;
+
+	regmap_read(map, reg, &val);
+	val >>= shift;
+	val &= (BIT(width) - 1);
+
+	return val;
+}
+
+static struct regmap *regmap_from_node(struct device_node *np)
+{
+	struct regmap *map;
+
+	for ( ; np; ) {
+		np = of_get_parent(np);
+		if (!np)
+			return ERR_PTR(-EINVAL);
+
+		map = syscon_node_to_regmap(np);
+		if (!IS_ERR(map))
+			return map;
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+#define GATE_STAT_REG(reg)	(reg)
+#define GATE_EN_REG(reg)	((reg) + 0x4)
+#define GATE_DIS_REG(reg)	((reg) + 0x8)
+
+static int get_gate(struct regmap *map, u32 reg, u8 shift)
+{
+	unsigned int val;
+
+	regmap_read(map, GATE_STAT_REG(reg), &val);
+
+	return !!(val & BIT(shift));
+}
+
+static void set_gate(struct regmap *map, u32 reg, u8 shift, int enable)
+{
+	if (enable)
+		regmap_write(map, GATE_EN_REG(reg), BIT(shift));
+	else
+		regmap_write(map, GATE_DIS_REG(reg), BIT(shift));
+}
+
+void
+intel_fixed_rate_clk_setup(struct device_node *node,
+			   const struct fixed_rate_clk_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	unsigned long rate;
+	struct regmap *regmap;
+	u32 reg;
+
+	if (!data)
+		return;
+
+	if (of_property_read_string(node, "clock-output-names", &clk_name))
+		return;
+
+	if (of_property_read_u32(node, "clock-frequency", (u32 *)&rate))
+		rate = data->fixed_rate;
+	if (!rate) {
+		pr_err("clk(%s): Could not get fixed rate\n", clk_name);
+		return;
+	}
+
+	regmap = regmap_from_node(node);
+	if (IS_ERR(regmap))
+		return;
+
+	/* Register the fixed rate clock */
+	clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, rate);
+	if (IS_ERR(clk))
+		return;
+
+	/* Clock init */
+	if (of_property_read_u32(node, "reg", &reg)) {
+		pr_err("%s no reg definition\n", node->name);
+		return;
+	}
+
+	set_clk_val(regmap, reg, data->shift, data->width, data->setval);
+
+	/* Register clock provider */
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+static int gate_clk_enable(struct clk_hw *hw)
+{
+	struct gate_clk *clk;
+
+	clk = to_gate_clk(hw);
+	set_gate(clk->map, clk->reg, clk->bit_idx, 1);
+	return 0;
+}
+
+static void gate_clk_disable(struct clk_hw *hw)
+{
+	struct gate_clk *clk;
+
+	clk = to_gate_clk(hw);
+	set_gate(clk->map, clk->reg, clk->bit_idx, 0);
+}
+
+static int gate_clk_is_enabled(struct clk_hw *hw)
+{
+	struct gate_clk *clk;
+
+	clk = to_gate_clk(hw);
+	return get_gate(clk->map, clk->reg, clk->bit_idx);
+}
+
+static const struct clk_ops gate_clk_ops = {
+	.enable = gate_clk_enable,
+	.disable = gate_clk_disable,
+	.is_enabled = gate_clk_is_enabled,
+};
+
+static struct clk *gate_clk_register(struct device *dev, const char *name,
+				     const char *parent_name,
+				     unsigned long flags,
+				     struct regmap *map, unsigned int reg,
+				     u8 bit_idx, unsigned int clk_gate_flags)
+{
+	struct gate_clk *gate;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	/* Allocate the gate */
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &gate_clk_ops;
+	init.flags = flags | CLK_IS_BASIC;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	/* Struct gate_clk assignments */
+	gate->map = map;
+	gate->reg = reg;
+	gate->bit_idx = bit_idx;
+	gate->flags = clk_gate_flags;
+	gate->hw.init = &init;
+
+	clk = clk_register(dev, &gate->hw);
+	if (IS_ERR(clk)) {
+		pr_err("0x%4x %d %s %d %d %s\n", (u32)reg, init.num_parents,
+		       parent_name, bit_idx, clk_gate_flags, name);
+		kfree(gate);
+	}
+
+	return clk;
+}
+
+void
+intel_gate_clk_setup(struct device_node *node, const struct gate_clk_data *data)
+{
+	struct clk_onecell_data *clk_data;
+	const char *clk_parent;
+	const char *clk_name = node->name;
+	struct regmap *regmap;
+	unsigned int reg;
+	int i, j, num;
+	unsigned int val;
+
+	if (!data || !data->reg_size) {
+		pr_err("%s: register bit size cannot be 0!\n", __func__);
+		return;
+	}
+
+	regmap = regmap_from_node(node);
+	if (IS_ERR(regmap))
+		return;
+
+	if (of_property_read_u32(node, "reg", &reg)) {
+		pr_err("%s no reg definition\n", node->name);
+		return;
+	}
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+
+	/* Size probe and memory allocation */
+	num = find_last_bit(&data->mask, data->reg_size);
+	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->clks = kcalloc(num + 1, sizeof(struct clk *), GFP_KERNEL);
+	if (!clk_data->clks)
+		goto __clkarr_alloc_fail;
+
+	i = 0;
+	j = 0;
+	for_each_set_bit(i, &data->mask, data->reg_size) {
+		of_property_read_string_index(node, "clock-output-names",
+					      j, &clk_name);
+
+		clk_data->clks[j] = gate_clk_register(NULL, clk_name,
+						      clk_parent, 0, regmap,
+						      reg, i, 0);
+		WARN_ON(IS_ERR(clk_data->clks[j]));
+
+		j++;
+	}
+
+	/* Adjust to the real max */
+	clk_data->clk_num = num + 1;
+
+	/* Initial gate default setting */
+	if (data->flags & CLK_INIT_DEF_CFG_REQ) {
+		val = (unsigned int)data->def_onoff;
+		if (val)
+			regmap_write(regmap, GATE_EN_REG(reg), val);
+		val = (((unsigned int)(~data->def_onoff)) & data->mask);
+		if (val)
+			regmap_write(regmap, GATE_DIS_REG(reg), val);
+	}
+
+	/* Register to clock provider */
+	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+	return;
+
+__clkarr_alloc_fail:
+	kfree(clk_data);
+}
+
+static unsigned long div_recalc_rate(struct div_clk *div,
+				     unsigned long parent_rate,
+				     unsigned int val)
+{
+	return divider_recalc_rate(&div->hw, parent_rate,
+			val, div->div_table, div->flags, div->width);
+}
+
+static unsigned long div_clk_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	struct div_clk *div = to_div_clk(hw);
+	unsigned int val;
+
+	val = get_clk_val(div->map, div->reg, div->shift, div->width);
+
+	return div_recalc_rate(div, parent_rate, val);
+}
+
+static long div_clk_round_rate(struct clk_hw *hw,
+			       unsigned long rate, unsigned long *prate)
+{
+	struct div_clk *div = to_div_clk(hw);
+
+	return divider_round_rate(hw, rate, prate,
+				  div->div_table, div->width, div->flags);
+}
+
+static int div_set_rate(struct div_clk *div, unsigned long rate,
+			unsigned long parent_rate)
+{
+	unsigned int val;
+
+	val = divider_get_val(rate, parent_rate, div->div_table,
+			      div->width, div->flags);
+	set_clk_val(div->map, div->reg, div->shift, div->width, val);
+
+	return 0;
+}
+
+static int div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	struct div_clk *div = to_div_clk(hw);
+
+	return div_set_rate(div, rate, parent_rate);
+}
+
+static const struct clk_ops clk_div_ops = {
+	.recalc_rate = div_clk_recalc_rate,
+	.round_rate = div_clk_round_rate,
+	.set_rate = div_clk_set_rate,
+};
+
+static struct clk *div_clk_register(struct device *dev, const char *name,
+				    const char *parent_name,
+				    unsigned long flags,
+				    struct regmap *map, unsigned int reg,
+				    const struct div_clk_data *data)
+{
+	struct div_clk *div;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	/* Allocate the divider clock*/
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &clk_div_ops;
+	init.flags = flags | CLK_IS_BASIC;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	/* Struct clk_divider assignments */
+	div->map = map;
+	div->reg = reg;
+	div->shift = data->shift;
+	div->width = data->width;
+	div->flags = data->flags;
+	div->div_table = data->div_table;
+	div->hw.init = &init;
+	div->tbl_sz = data->tbl_sz;
+
+	/* Register the clock */
+	clk = clk_register(dev, &div->hw);
+	if (IS_ERR(clk))
+		kfree(div);
+
+	return clk;
+}
+
+void
+intel_div_clk_setup(struct device_node *node, const struct div_clk_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	const char *clk_parent;
+	struct regmap *map;
+	unsigned int reg;
+
+	if (!data)
+		return;
+
+	map = regmap_from_node(node);
+	if (IS_ERR(map))
+		return;
+
+	if (of_property_read_u32(node, "reg", &reg)) {
+		pr_err("%s no reg definition\n", node->name);
+		return;
+	}
+
+	if (of_property_read_string(node, "clock-output-names", &clk_name))
+		return;
+	clk_parent = of_clk_get_parent_name(node, 0);
+
+	clk = div_clk_register(NULL, clk_name, clk_parent, 0, map, reg, data);
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+void
+intel_cluster_div_clk_setup(struct device_node *node,
+			    const struct div_clk_data *data, u32 num)
+{
+	struct clk_onecell_data *clk_data;
+	const char *clk_name;
+	const char *clk_parent;
+	struct regmap *regmap;
+	unsigned int reg;
+	int i;
+
+	if (!data || !num) {
+		pr_err("%s: invalid array or array size!\n", __func__);
+		return;
+	}
+
+	regmap = regmap_from_node(node);
+	if (IS_ERR(regmap))
+		return;
+
+	if (of_property_read_u32(node, "reg", &reg)) {
+		pr_err("%s no reg definition\n", node->name);
+		return;
+	}
+
+	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+	clk_data->clks = kcalloc(num, sizeof(struct clk *), GFP_KERNEL);
+	if (!clk_data->clks)
+		goto __clkarr_alloc_fail;
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+
+	for (i = 0; i < num; i++) {
+		of_property_read_string_index(node, "clock-output-names",
+					      i, &clk_name);
+		clk_data->clks[i] = div_clk_register(NULL, clk_name, clk_parent,
+						     0, regmap, reg, &data[i]);
+		WARN_ON(IS_ERR(clk_data->clks[i]));
+	}
+	clk_data->clk_num = num + 1;
+
+	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+	return;
+
+__clkarr_alloc_fail:
+	kfree(clk_data);
+}
+
+static unsigned int mux_parent_from_table(const u32 *table,
+					  unsigned int val, unsigned int num)
+{
+	unsigned int i;
+
+	for (i = 0; i < num; i++)
+		if (table[i] == val)
+			return i;
+
+	return -EINVAL;
+}
+
+static u8 mux_clk_get_parent(struct clk_hw *hw)
+{
+	struct mux_clk *mux = to_mux_clk(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+	unsigned int val;
+
+	val = get_clk_val(mux->map, mux->reg, mux->shift, mux->width);
+	if (mux->table)
+		return mux_parent_from_table(mux->table, val, num_parents);
+
+	if (val && (mux->flags & CLK_MUX_INDEX_BIT))
+		val = ffs(val) - 1;
+	if (val && (mux->flags & CLK_MUX_INDEX_ONE))
+		val -= 1;
+	if (val >= num_parents)
+		return -EINVAL;
+
+	return val;
+}
+
+static int mux_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct mux_clk *mux = to_mux_clk(hw);
+
+	if (mux->table) {
+		index = mux->table[index];
+	} else {
+		if (mux->flags & CLK_MUX_INDEX_BIT)
+			index = BIT(index);
+		if (mux->flags & CLK_MUX_INDEX_ONE)
+			index += 1;
+	}
+
+	set_clk_val(mux->map, mux->reg, mux->shift, mux->width, index);
+
+	return 0;
+}
+
+static const struct clk_ops mux_clk_ops = {
+	.get_parent = mux_clk_get_parent,
+	.set_parent = mux_clk_set_parent,
+	.determine_rate = __clk_mux_determine_rate,
+};
+
+static struct clk *mux_clk_register(struct device *dev, const char *name,
+				    const char * const *parent_names,
+				    u8 num_parents, unsigned long flags,
+				    struct regmap *map, unsigned int reg,
+				    const struct mux_clk_data *data)
+{
+	struct mux_clk *mux;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	/* allocate mux clk */
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	/* struct init assignments */
+	init.name = name;
+	init.flags = flags | CLK_IS_BASIC;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.ops = &mux_clk_ops;
+
+	/* struct mux_clk assignments */
+	mux->map = map;
+	mux->reg = reg;
+	mux->shift = data->shift;
+	mux->width = data->width;
+	mux->flags = data->clk_flags;
+	mux->table = data->table;
+	mux->hw.init = &init;
+
+	clk = clk_register(dev, &mux->hw);
+	if (IS_ERR(clk))
+		kfree(mux);
+
+	return clk;
+}
+
+void
+intel_mux_clk_setup(struct device_node *node, const struct mux_clk_data *data)
+{
+	struct clk *clk;
+	const char *clk_name;
+	const char **parents;
+	unsigned int num_parents;
+	struct regmap *map;
+	unsigned int reg;
+
+	if (!data)
+		return;
+
+	map = regmap_from_node(node);
+	if (IS_ERR(map))
+		return;
+
+	if (of_property_read_string(node, "clock-output-names", &clk_name)) {
+		pr_err("%s: no output clock name!\n", node->name);
+		return;
+	}
+
+	if (of_property_read_u32(node, "reg", &reg)) {
+		pr_err("%s no reg definition\n", node->name);
+		return;
+	}
+
+	num_parents = of_clk_get_parent_count(node);
+	if (num_parents) {
+		parents = kmalloc_array(num_parents,
+					sizeof(char *), GFP_KERNEL);
+		if (!parents)
+			return;
+		of_clk_parent_fill(node, parents, num_parents);
+	} else {
+		pr_err("%s: mux clk no parent!\n", __func__);
+		return;
+	}
+
+	clk = mux_clk_register(NULL, clk_name, parents, num_parents,
+			       data->flags, map, reg, data);
+	if (IS_ERR(clk))
+		goto __mux_clk_fail;
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	return;
+
+__mux_clk_fail:
+	kfree(parents);
+}
+
+static int gate_clk_dummy_enable(struct clk_hw *hw)
+{
+	struct gate_dummy_clk *clk;
+
+	clk = to_clk_gate_dummy(hw);
+	clk->clk_status = 1;
+
+	return 0;
+}
+
+static void gate_clk_dummy_disable(struct clk_hw *hw)
+{
+	struct gate_dummy_clk *clk;
+
+	clk = to_clk_gate_dummy(hw);
+	clk->clk_status = 0;
+}
+
+static int gate_clk_dummy_is_enabled(struct clk_hw *hw)
+{
+	struct gate_dummy_clk *clk;
+
+	clk = to_clk_gate_dummy(hw);
+	return clk->clk_status;
+}
+
+static const struct clk_ops clk_gate_dummy_ops = {
+	.enable = gate_clk_dummy_enable,
+	.disable = gate_clk_dummy_disable,
+	.is_enabled = gate_clk_dummy_is_enabled,
+};
+
+static struct clk
+*clk_register_gate_dummy(struct device *dev,
+			 const char *name,
+			 const char *parent_name,
+			 unsigned long flags,
+			 const struct gate_dummy_clk_data *data)
+{
+	struct gate_dummy_clk *gate_clk;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	/* Allocate the gate_dummy clock*/
+	gate_clk = kzalloc(sizeof(*gate_clk), GFP_KERNEL);
+	if (!gate_clk)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &clk_gate_dummy_ops;
+	init.flags = flags | CLK_IS_BASIC;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+	gate_clk->hw.init = &init;
+
+	/* Struct gate_clk assignments */
+	if (data->flags & CLK_INIT_DEF_CFG_REQ)
+		gate_clk->clk_status = data->def_val & 0x1;
+
+	/* Register the clock */
+	clk = clk_register(dev, &gate_clk->hw);
+	if (IS_ERR(clk))
+		kfree(gate_clk);
+
+	return clk;
+}
+
+void
+intel_gate_dummy_clk_setup(struct device_node *node,
+			   const struct gate_dummy_clk_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+
+	if (!data)
+		return;
+
+	if (of_property_read_string(node, "clock-output-names", &clk_name))
+		return;
+
+	clk = clk_register_gate_dummy(NULL, clk_name, NULL, 0, data);
+	if (IS_ERR(clk)) {
+		pr_err("%s: dummy gate clock register fail!\n", __func__);
+		return;
+	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
diff --git a/drivers/clk/intel/clk-cgu-api.h b/drivers/clk/intel/clk-cgu-api.h
new file mode 100644
index 000000000000..3a8d7e47ba58
--- /dev/null
+++ b/drivers/clk/intel/clk-cgu-api.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __INTEL_CLK_API_H
+#define __INTEL_CLK_API_H
+
+/*
+ *  Copyright(c) 2016 Intel Corporation.
+ *  Zhu YiXin <Yixin.zhu@intel.com>
+ *
+ */
+
+struct div_clk_data {
+	u8 shift;
+	u8 width;
+	const unsigned int tbl_sz;
+	const struct clk_div_table *div_table;
+	unsigned long flags;
+};
+
+struct mux_clk_data {
+	u8 shift;
+	u8 width;
+	const u32 *table;
+	unsigned long flags;
+	unsigned long clk_flags;
+};
+
+struct gate_clk_data {
+	unsigned long mask;
+	unsigned long def_onoff;
+	u8 reg_size;
+	unsigned long flags;
+};
+
+struct gate_dummy_clk_data {
+	unsigned int def_val;
+	unsigned long flags;
+};
+
+struct fixed_rate_clk_data {
+	u8 shift;
+	u8 width;
+	unsigned long fixed_rate;
+	unsigned int setval;
+};
+
+struct gate_dummy_clk {
+	struct clk_hw hw;
+	unsigned int clk_status;
+};
+
+struct div_clk {
+	struct clk_hw hw;
+	struct regmap *map;
+	unsigned int reg;
+	u8 shift;
+	u8 width;
+	unsigned int flags;
+	const struct clk_div_table *div_table;
+	unsigned int tbl_sz;
+};
+
+struct gate_clk {
+	struct clk_hw hw;
+	struct regmap *map;
+	unsigned int reg;
+	u8 bit_idx;
+	unsigned int flags;
+};
+
+struct mux_clk {
+	struct clk_hw hw;
+	struct regmap *map;
+	unsigned int reg;
+	const u32 *table;
+	u8 shift;
+	u8 width;
+	unsigned int flags;
+};
+
+/**
+ * struct clk_fixed_factor_frac - fixed multiplier/divider/fraction clock
+ *
+ * @hw:		handle between common and hardware-specific interfaces
+ * @mult:	multiplier(N)
+ * @div:	divider(M)
+ * @frac:	fraction(K)
+ * @frac_div:	fraction divider(D)
+ *
+ * Clock with a fixed multiplier, divider and fraction.
+ * The output frequency formula is clk = parent clk * (N+K/D)/M.
+ * Implements .recalc_rate, .set_rate and .round_rate
+ */
+
+struct clk_fixed_factor_frac {
+	struct clk_hw	hw;
+	unsigned int	mult;
+	unsigned int	div;
+	unsigned int	frac;
+	unsigned int	frac_div;
+};
+
+#define INTEL_FIXED_FACTOR_PLLCLK	"intel,fixed-factor-pllclk"
+#define INTEL_FIXED_FACTOR_FRAC_PLLCLK	"intel,fixed-factor-frac-pllclk"
+
+#define CLK_INIT_DEF_CFG_REQ		BIT(0)
+
+void intel_gate_clk_setup(struct device_node *np,
+			  const struct gate_clk_data *data);
+void intel_mux_clk_setup(struct device_node *np,
+			 const struct mux_clk_data *data);
+void intel_fixed_rate_clk_setup(struct device_node *np,
+				const struct fixed_rate_clk_data *data);
+void intel_div_clk_setup(struct device_node *np,
+			 const struct div_clk_data *data);
+void intel_gate_dummy_clk_setup(struct device_node *np,
+				const struct gate_dummy_clk_data *data);
+void intel_cluster_div_clk_setup(struct device_node *np,
+				 const struct div_clk_data *data, u32 num);
+
+#endif /* __INTEL_CLK_API_H */
diff --git a/drivers/clk/intel/clk-grx500.c b/drivers/clk/intel/clk-grx500.c
new file mode 100644
index 000000000000..c61b7ba06758
--- /dev/null
+++ b/drivers/clk/intel/clk-grx500.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2016 Intel Corporation.
+ *  Zhu YiXin <Yixin.zhu@intel.com>
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+#include <dt-bindings/clock/intel,grx500-clk.h>
+#include "clk-cgu-api.h"
+
+/* Intel GRX500 CGU device tree "compatible" strings */
+#define INTEL_GRX500_DT_PLL0A_CLK	"intel,grx500-pll0a-clk"
+#define INTEL_GRX500_DT_PLL0B_CLK	"intel,grx500-pll0b-clk"
+#define INTEL_GRX500_DT_PCIE_CLK	"intel,grx500-pcie-clk"
+#define INTEL_GRX500_DT_CPU_CLK		"intel,grx500-cpu-clk"
+#define INTEL_GRX500_DT_GATE0_CLK	"intel,grx500-gate0-clk"
+#define INTEL_GRX500_DT_GATE1_CLK	"intel,grx500-gate1-clk"
+#define INTEL_GRX500_DT_GATE2_CLK	"intel,grx500-gate2-clk"
+#define INTEL_GRX500_DT_VOICE_CLK	"intel,grx500-voice-clk"
+#define INTEL_GRX500_DT_GATE_I2C_CLK	"intel,grx500-gate-dummy-clk"
+
+/* clock shift and width */
+#define CBM_CLK_SHIFT		0
+#define CBM_CLK_WIDTH		4
+#define NGI_CLK_SHIFT		4
+#define NGI_CLK_WIDTH		4
+#define SSX4_CLK_SHIFT		8
+#define SSX4_CLK_WIDTH		4
+#define CPU0_CLK_SHIFT		12
+#define CPU0_CLK_WIDTH		4
+
+#define PAE_CLK_SHIFT		0
+#define PAE_CLK_WIDTH		4
+#define GSWIP_CLK_SHIFT		4
+#define GSWIP_CLK_WIDTH		4
+#define DDR_CLK_SHIFT		8
+#define DDR_CLK_WIDTH		4
+#define CPU1_CLK_SHIFT		12
+#define CPU1_CLK_WIDTH		4
+
+#define PCIE_CLK_SHIFT		12
+#define PCIE_CLK_WIDTH		2
+
+#define CPU_CLK_SHIFT		29
+#define CPU_CLK_WIDTH		1
+
+#define VOICE_CLK_SHIFT		14
+#define VOICE_CLK_WIDTH		2
+
+/* Gate clock mask */
+#define GATE0_CLK_MASK		0xCF
+#define GATE1_CLK_MASK		0x1EF27FE4
+#define GATE2_CLK_MASK		0x2020002
+
+static const struct clk_div_table pll_div[] = {
+	{1,	2},
+	{2,	3},
+	{3,	4},
+	{4,	5},
+	{5,	6},
+	{6,	8},
+	{7,	10},
+	{8,	12},
+	{9,	16},
+	{10,	20},
+	{11,	24},
+	{12,	32},
+	{13,	40},
+	{14,	48},
+	{15,	64}
+};
+
+static const struct gate_dummy_clk_data grx500_clk_gate_i2c_data __initconst = {
+	0
+};
+
+static void __init grx500_clk_gate_i2c_setup(struct device_node *node)
+{
+	intel_gate_dummy_clk_setup(node, &grx500_clk_gate_i2c_data);
+}
+
+CLK_OF_DECLARE(grx500_gatei2cclk, INTEL_GRX500_DT_GATE_I2C_CLK,
+	       grx500_clk_gate_i2c_setup);
+
+static const struct fixed_rate_clk_data grx500_clk_voice_data __initconst = {
+	.shift = VOICE_CLK_SHIFT,
+	.width = VOICE_CLK_WIDTH,
+	.setval = 0x2,
+};
+
+static void __init grx500_clk_voice_setup(struct device_node *node)
+{
+	intel_fixed_rate_clk_setup(node, &grx500_clk_voice_data);
+}
+
+CLK_OF_DECLARE(grx500_voiceclk, INTEL_GRX500_DT_VOICE_CLK,
+	       grx500_clk_voice_setup);
+
+static const struct gate_clk_data grx500_clk_gate2_data __initconst = {
+	.mask = GATE2_CLK_MASK,
+	.reg_size = 32,
+};
+
+static void __init grx500_clk_gate2_setup(struct device_node *node)
+{
+	intel_gate_clk_setup(node, &grx500_clk_gate2_data);
+}
+
+CLK_OF_DECLARE(grx500_gate2clk, INTEL_GRX500_DT_GATE2_CLK,
+	       grx500_clk_gate2_setup);
+
+static const struct gate_clk_data grx500_clk_gate1_data __initconst = {
+	.mask = GATE1_CLK_MASK,
+	.def_onoff = 0x14000600,
+	.reg_size = 32,
+	.flags = CLK_INIT_DEF_CFG_REQ,
+};
+
+static void __init grx500_clk_gate1_setup(struct device_node *node)
+{
+	intel_gate_clk_setup(node, &grx500_clk_gate1_data);
+}
+
+CLK_OF_DECLARE(grx500_gate1clk, INTEL_GRX500_DT_GATE1_CLK,
+	       grx500_clk_gate1_setup);
+
+static const struct gate_clk_data grx500_clk_gate0_data __initconst = {
+	.mask = GATE0_CLK_MASK,
+	.def_onoff = GATE0_CLK_MASK,
+	.reg_size = 32,
+	.flags = CLK_INIT_DEF_CFG_REQ,
+};
+
+static void __init grx500_clk_gate0_setup(struct device_node *node)
+{
+	intel_gate_clk_setup(node, &grx500_clk_gate0_data);
+}
+
+CLK_OF_DECLARE(grx500_gate0clk, INTEL_GRX500_DT_GATE0_CLK,
+	       grx500_clk_gate0_setup);
+
+static const struct mux_clk_data grx500_clk_cpu_data __initconst = {
+	.shift = CPU_CLK_SHIFT,
+	.width = CPU_CLK_WIDTH,
+	.flags = CLK_SET_RATE_PARENT,
+};
+
+static void __init grx500_clk_cpu_setup(struct device_node *node)
+{
+	intel_mux_clk_setup(node, &grx500_clk_cpu_data);
+}
+
+CLK_OF_DECLARE(grx500_cpuclk, INTEL_GRX500_DT_CPU_CLK,
+	       grx500_clk_cpu_setup);
+
+static const struct div_clk_data grx500_clk_pcie_data __initconst = {
+	.shift = PCIE_CLK_SHIFT,
+	.width = PCIE_CLK_WIDTH,
+	.div_table = pll_div,
+};
+
+static void __init grx500_clk_pcie_setup(struct device_node *node)
+{
+	intel_div_clk_setup(node, &grx500_clk_pcie_data);
+}
+
+CLK_OF_DECLARE(grx500_pcieclk, INTEL_GRX500_DT_PCIE_CLK,
+	       grx500_clk_pcie_setup);
+
+static const struct div_clk_data grx500_clk_pll0b[] __initconst = {
+	{
+		.shift = PAE_CLK_SHIFT,
+		.width = PAE_CLK_WIDTH,
+		.div_table = pll_div,
+	},
+	{
+		.shift = GSWIP_CLK_SHIFT,
+		.width = GSWIP_CLK_WIDTH,
+		.div_table = pll_div,
+	},
+	{
+		.shift = DDR_CLK_SHIFT,
+		.width = DDR_CLK_WIDTH,
+		.div_table = pll_div,
+	},
+	{
+		.shift = CPU1_CLK_SHIFT,
+		.width = CPU1_CLK_WIDTH,
+		.div_table = pll_div,
+	},
+};
+
+static void __init grx500_clk_pll0b_setup(struct device_node *node)
+{
+	intel_cluster_div_clk_setup(node, grx500_clk_pll0b,
+				    ARRAY_SIZE(grx500_clk_pll0b));
+}
+
+CLK_OF_DECLARE(grx500_pll0bclk, INTEL_GRX500_DT_PLL0B_CLK,
+	       grx500_clk_pll0b_setup);
+
+static const struct div_clk_data grx500_clk_pll0a[] __initconst = {
+	{
+		.shift = CBM_CLK_SHIFT,
+		.width = CBM_CLK_WIDTH,
+		.div_table = pll_div,
+	},
+	{
+		.shift = NGI_CLK_SHIFT,
+		.width = NGI_CLK_WIDTH,
+		.div_table = pll_div,
+	},
+	{
+		.shift = SSX4_CLK_SHIFT,
+		.width = SSX4_CLK_WIDTH,
+		.div_table = pll_div,
+	},
+	{
+		.shift = CPU0_CLK_SHIFT,
+		.width = CPU0_CLK_WIDTH,
+		.div_table = pll_div,
+	},
+};
+
+static void __init grx500_clk_pll0a_setup(struct device_node *node)
+{
+	intel_cluster_div_clk_setup(node, grx500_clk_pll0a,
+				    ARRAY_SIZE(grx500_clk_pll0a));
+}
+
+CLK_OF_DECLARE(grx500_pll0aclk, INTEL_GRX500_DT_PLL0A_CLK,
+	       grx500_clk_pll0a_setup);
diff --git a/include/dt-bindings/clock/intel,grx500-clk.h b/include/dt-bindings/clock/intel,grx500-clk.h
new file mode 100644
index 000000000000..eb1114636504
--- /dev/null
+++ b/include/dt-bindings/clock/intel,grx500-clk.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (C) 2016 Intel Corporation.
+ *  Zhu YiXin <Yixin.zhu@intel.com>
+ *
+ */
+
+#ifndef __INTEL_GRX500_CLK_H
+#define __INTEL_GRX500_CLK_H
+
+/* clocks under pll0a-clk */
+#define CBM_CLK			0
+#define NGI_CLK			1
+#define SSX4_CLK		2
+#define CPU0_CLK		3
+
+/* clocks under pll0b-clk */
+#define PAE_CLK			0
+#define GSWIP_CLK		1
+#define DDR_CLK			2
+#define CPU1_CLK		3
+
+/* clocks under lcpll-clk */
+#define GRX500_PCIE_CLK		0
+
+/* clocks under gate0-clk */
+#define GATE_XBAR0_CLK		0
+#define GATE_XBAR1_CLK		1
+#define GATE_XBAR2_CLK		2
+#define GATE_XBAR3_CLK		3
+#define GATE_XBAR6_CLK		4
+#define GATE_XBAR7_CLK		5
+
+/* clocks under gate1-clk */
+#define GATE_V_CODEC_CLK	0
+#define GATE_DMA0_CLK		1
+#define GATE_USB0_CLK		2
+#define GATE_SPI1_CLK		3
+#define GATE_SPI0_CLK		4
+#define GATE_CBM_CLK		5
+#define GATE_EBU_CLK		6
+#define GATE_SSO_CLK		7
+#define GATE_GPTC0_CLK		8
+#define GATE_GPTC1_CLK		9
+#define GATE_GPTC2_CLK		10
+#define GATE_URT_CLK		11
+#define GATE_EIP97_CLK		12
+#define GATE_EIP123_CLK		13
+#define GATE_TOE_CLK		14
+#define GATE_MPE_CLK		15
+#define GATE_TDM_CLK		16
+#define GATE_PAE_CLK		17
+#define GATE_USB1_CLK		18
+#define GATE_GSWIP_CLK		19
+
+/* clocks under gate2-clk */
+#define GATE_PCIE0_CLK		0
+#define GATE_PCIE1_CLK		1
+#define GATE_PCIE2_CLK		2
+
+#endif /* __INTEL_GRX500_CLK_H */
-- 
2.11.0

^ permalink raw reply related

* [PATCH 3/7] MIPS: intel: Add initial support for Intel MIPS SoCs
From: Songjun Wu @ 2018-06-12  5:40 UTC (permalink / raw)
  To: hua.ma, yixin.zhu, chuanhua.lei
  Cc: linux-mips, qi-ming.wu, linux-clk, linux-serial, devicetree,
	Songjun Wu, James Hogan, linux-kernel, Rob Herring, Ralf Baechle,
	Mark Rutland
In-Reply-To: <20180612054034.4969-1-songjun.wu@linux.intel.com>

From: Hua Ma <hua.ma@linux.intel.com>

Add initial support for Intel MIPS interAptiv SoCs made by Intel.
This series will add support for the GRX500 family.

The series allows booting a minimal system using a initramfs.

Signed-off-by: Hua ma <hua.ma@linux.intel.com>
Signed-off-by: Songjun Wu <songjun.wu@linux.intel.com>
---

 arch/mips/Kbuild.platforms                         |   1 +
 arch/mips/Kconfig                                  |  36 ++++
 arch/mips/boot/dts/Makefile                        |   1 +
 arch/mips/boot/dts/intel-mips/Makefile             |   3 +
 arch/mips/boot/dts/intel-mips/easy350_anywan.dts   |  20 +++
 arch/mips/boot/dts/intel-mips/xrx500.dtsi          | 196 +++++++++++++++++++++
 arch/mips/configs/grx500_defconfig                 | 165 +++++++++++++++++
 .../asm/mach-intel-mips/cpu-feature-overrides.h    |  61 +++++++
 arch/mips/include/asm/mach-intel-mips/ioremap.h    |  39 ++++
 arch/mips/include/asm/mach-intel-mips/irq.h        |  17 ++
 .../asm/mach-intel-mips/kernel-entry-init.h        |  76 ++++++++
 arch/mips/include/asm/mach-intel-mips/spaces.h     |  29 +++
 arch/mips/include/asm/mach-intel-mips/war.h        |  18 ++
 arch/mips/intel-mips/Kconfig                       |  22 +++
 arch/mips/intel-mips/Makefile                      |   3 +
 arch/mips/intel-mips/Platform                      |  11 ++
 arch/mips/intel-mips/irq.c                         |  36 ++++
 arch/mips/intel-mips/prom.c                        | 184 +++++++++++++++++++
 arch/mips/intel-mips/time.c                        |  56 ++++++
 19 files changed, 974 insertions(+)
 create mode 100644 arch/mips/boot/dts/intel-mips/Makefile
 create mode 100644 arch/mips/boot/dts/intel-mips/easy350_anywan.dts
 create mode 100644 arch/mips/boot/dts/intel-mips/xrx500.dtsi
 create mode 100644 arch/mips/configs/grx500_defconfig
 create mode 100644 arch/mips/include/asm/mach-intel-mips/cpu-feature-overrides.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/ioremap.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/irq.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/kernel-entry-init.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/spaces.h
 create mode 100644 arch/mips/include/asm/mach-intel-mips/war.h
 create mode 100644 arch/mips/intel-mips/Kconfig
 create mode 100644 arch/mips/intel-mips/Makefile
 create mode 100644 arch/mips/intel-mips/Platform
 create mode 100644 arch/mips/intel-mips/irq.c
 create mode 100644 arch/mips/intel-mips/prom.c
 create mode 100644 arch/mips/intel-mips/time.c

diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index ac7ad54f984f..bcd647060f3e 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -12,6 +12,7 @@ platforms += cobalt
 platforms += dec
 platforms += emma
 platforms += generic
+platforms += intel-mips
 platforms += jazz
 platforms += jz4740
 platforms += lantiq
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 225c95da23ce..c82cebeb6192 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -404,6 +404,41 @@ config LANTIQ
 	select ARCH_HAS_RESET_CONTROLLER
 	select RESET_CONTROLLER
 
+config INTEL_MIPS
+	bool "Intel MIPS interAptiv SoC based platforms"
+	select ARCH_HAS_RESET_CONTROLLER
+	select ARCH_SUPPORTS_MSI
+	select BOOT_RAW
+	select CEVT_R4K
+	select COMMON_CLK
+	select CPU_MIPS32_3_5_EVA
+	select CPU_MIPS32_3_5_FEATURES
+	select CPU_MIPSR2_IRQ_EI
+	select CPU_MIPSR2_IRQ_VI
+	select CSRC_R4K
+	select DMA_NONCOHERENT
+	select GENERIC_ISA_DMA
+	select GPIOLIB
+	select HW_HAS_PCI
+	select IRQ_MIPS_CPU
+	select MFD_CORE
+	select MFD_SYSCON
+	select MIPS_CPU_SCACHE
+	select MIPS_GIC
+	select PCI_DRIVERS_GENERIC
+	select RESET_CONTROLLER
+	select SYS_HAS_CPU_MIPS32_R1
+	select SYS_HAS_CPU_MIPS32_R2
+	select SYS_HAS_CPU_MIPS32_R3_5
+	select SYS_HAS_EARLY_PRINTK
+	select SYS_SUPPORTS_BIG_ENDIAN
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_MIPS_CPS
+	select SYS_SUPPORTS_MULTITHREADING
+	select SYS_SUPPORTS_ZBOOT
+	select TIMER_OF
+	select USE_OF
+
 config LASAT
 	bool "LASAT Networks platforms"
 	select CEVT_R4K
@@ -1010,6 +1045,7 @@ source "arch/mips/bcm47xx/Kconfig"
 source "arch/mips/bcm63xx/Kconfig"
 source "arch/mips/bmips/Kconfig"
 source "arch/mips/generic/Kconfig"
+source "arch/mips/intel-mips/Kconfig"
 source "arch/mips/jazz/Kconfig"
 source "arch/mips/jz4740/Kconfig"
 source "arch/mips/lantiq/Kconfig"
diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile
index 1e79cab8e269..05f52f279047 100644
--- a/arch/mips/boot/dts/Makefile
+++ b/arch/mips/boot/dts/Makefile
@@ -3,6 +3,7 @@ subdir-y	+= brcm
 subdir-y	+= cavium-octeon
 subdir-y	+= img
 subdir-y	+= ingenic
+subdir-y	+= intel-mips
 subdir-y	+= lantiq
 subdir-y	+= mscc
 subdir-y	+= mti
diff --git a/arch/mips/boot/dts/intel-mips/Makefile b/arch/mips/boot/dts/intel-mips/Makefile
new file mode 100644
index 000000000000..b16c0081639c
--- /dev/null
+++ b/arch/mips/boot/dts/intel-mips/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_DTB_INTEL_MIPS_GRX500)	+= easy350_anywan.dtb
+obj-y	+= $(patsubst %.dtb, %.dtb.o, $(dtb-y))
diff --git a/arch/mips/boot/dts/intel-mips/easy350_anywan.dts b/arch/mips/boot/dts/intel-mips/easy350_anywan.dts
new file mode 100644
index 000000000000..40177f6cee1e
--- /dev/null
+++ b/arch/mips/boot/dts/intel-mips/easy350_anywan.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/mips-gic.h>
+#include <dt-bindings/clock/intel,grx500-clk.h>
+
+#include "xrx500.dtsi"
+
+/ {
+	model = "EASY350 ANYWAN (GRX350) Main model";
+	chosen {
+		bootargs = "earlycon=lantiq,0x16600000 clk_ignore_unused";
+		stdout-path = "serial0";
+	};
+
+	memory@0 {
+		device_type = "memory";
+		reg = <0x20000000 0x0e000000>;
+	};
+};
diff --git a/arch/mips/boot/dts/intel-mips/xrx500.dtsi b/arch/mips/boot/dts/intel-mips/xrx500.dtsi
new file mode 100644
index 000000000000..04a068d6d96b
--- /dev/null
+++ b/arch/mips/boot/dts/intel-mips/xrx500.dtsi
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "intel,xrx500";
+
+	aliases {
+		serial0 = &asc0;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "mti,interaptiv";
+			clocks = <&cpuclk>;
+			reg = <0>;
+		};
+
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "mti,interaptiv";
+			reg = <1>;
+		};
+	};
+
+	cpu_intc: interrupt-controller {
+		compatible = "mti,cpu-interrupt-controller";
+
+		interrupt-controller;
+		#interrupt-cells = <1>;
+	};
+
+	gic: gic@12320000 {
+		compatible = "mti,gic";
+		reg = <0x12320000 0x20000>;
+
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		/*
+		 * Declare the interrupt-parent even though the mti,gic
+		 * binding doesn't require it, such that the kernel can
+		 * figure out that cpu_intc is the root interrupt
+		 * controller & should be probed first.
+		 */
+		interrupt-parent = <&cpu_intc>;
+		mti,reserved-ipi-vectors = <56 8>;
+	};
+
+	cgu0: cgu@16200000 {
+		compatible = "syscon";
+		reg = <0x16200000 0x100000>;
+
+		clock {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			osc0: osc0 {
+				#clock-cells = <0>;
+				compatible = "fixed-clock";
+				clock-frequency = <40000000>;
+				clock-output-names = "osc40M";
+			};
+
+			pll0a: pll0a {
+				#clock-cells = <0>;
+				compatible = "fixed-factor-clock";
+				clock-mult = <0x3C>;
+				clock-div = <1>;
+				clocks = <&osc0>;
+				clock-output-names = "pll0a";
+			};
+
+			pll0b: pll0b {
+				#clock-cells = <0>;
+				compatible = "fixed-factor-clock";
+				clock-mult = <0x32>;
+				clock-div = <1>;
+				clocks = <&osc0>;
+				clock-output-names = "pll0b";
+			};
+
+			pll3: pll3 {
+				#clock-cells = <0>;
+				compatible = "fixed-factor-clock";
+				clock-mult = <0x64>;
+				clock-div = <1>;
+				clocks = <&osc0>;
+				clock-output-names = "lcpll3";
+			};
+
+			pll0aclk: pll0aclk {
+				#clock-cells = <1>;
+				compatible = "intel,grx500-pll0a-clk";
+				clocks = <&pll0a>;
+				reg = <0x8>;
+				clock-output-names = "cbm", "ngi",
+				"ssx4", "cpu0";
+			};
+
+			pll0bclk: pll0bclk {
+				#clock-cells = <1>;
+				compatible = "intel,grx500-pll0b-clk";
+				clocks = <&pll0b>;
+				reg = <0x38>;
+				clock-output-names = "pae", "gswip", "ddr",
+				"cpu1";
+			};
+
+			ddrphyclk: ddrphyclk {
+				#clock-cells = <0>;
+				compatible = "fixed-factor-clock";
+				clock-mult = <2>;
+				clock-div = <1>;
+				clocks = <&pll0bclk DDR_CLK>;
+				clock-output-names = "ddrphy";
+			};
+
+			pcieclk: pcieclk {
+				#clock-cells = <0>;
+				compatible = "intel,grx500-pcie-clk";
+				clocks = <&pll3>;
+				reg = <0x98>;
+				clock-output-names = "pcie";
+			};
+
+			cpuclk: cpuclk {
+				#clock-cells = <0>;
+				compatible = "intel,grx500-cpu-clk";
+				clocks = <&pll0aclk CPU0_CLK>,
+				<&pll0bclk CPU1_CLK>;
+				reg = <0x8>;
+				clock-output-names = "cpu";
+			};
+
+			clkgate0: clkgate0 {
+				#clock-cells = <1>;
+				compatible = "intel,grx500-gate0-clk";
+				reg = <0x114>;
+				clock-output-names = "gate_xbar0", "gate_xbar1",
+				"gate_xbar2", "gate_xbar3", "gate_xbar6",
+				"gate_xbar7";
+			};
+
+			clkgate1: clkgate1 {
+				#clock-cells = <1>;
+				compatible = "intel,grx500-gate1-clk";
+				reg = <0x120>;
+				clock-output-names = "gate_vcodec", "gate_dma0",
+				"gate_usb0", "gate_spi1", "gate_spi0",
+				"gate_cbm", "gate_ebu", "gate_sso",
+				"gate_gptc0", "gate_gptc1", "gate_gptc2",
+				"gate_urt", "gate_eip97", "gate_eip123",
+				"gate_toe", "gate_mpe", "gate_tdm", "gate_pae",
+				"gate_usb1", "gate_gswip";
+			};
+
+			clkgate2: clkgate2 {
+				#clock-cells = <1>;
+				compatible = "intel,grx500-gate2-clk";
+				reg = <0x130>;
+				clock-output-names = "gate_pcie0", "gate_pcie1",
+				"gate_pcie2";
+			};
+
+			voiceclk: voiceclk {
+				#clock-cells = <0>;
+				compatible = "intel,grx500-voice-clk";
+				clock-frequency = <8192000>;
+				reg = <0xc4>;
+				clock-output-names = "voice";
+			};
+
+			i2cclk: i2cclk {
+				#clock-cells = <0>;
+				compatible = "intel,grx500-gate-dummy-clk";
+				clock-output-names = "gate_i2c";
+			};
+		};
+	};
+
+	asc0: serial@16600000 {
+		compatible = "lantiq,asc";
+		reg = <0x16600000 0x100000>;
+
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SHARED 103 IRQ_TYPE_LEVEL_HIGH>,
+			<GIC_SHARED 105 IRQ_TYPE_LEVEL_HIGH>,
+			<GIC_SHARED 106 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&pll0aclk SSX4_CLK>, <&clkgate1 GATE_URT_CLK>;
+		clock-names = "freq", "asc";
+	};
+};
diff --git a/arch/mips/configs/grx500_defconfig b/arch/mips/configs/grx500_defconfig
new file mode 100644
index 000000000000..d353b74dddcd
--- /dev/null
+++ b/arch/mips/configs/grx500_defconfig
@@ -0,0 +1,165 @@
+CONFIG_INTEL_MIPS=y
+CONFIG_DTB_INTEL_MIPS_GRX500=y
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_SCHED_SMT=y
+# CONFIG_MIPS_MT_FPAFF is not set
+CONFIG_MIPS_CPS=y
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_CLEANCACHE=y
+CONFIG_FRONTSWAP=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSWAP=y
+CONFIG_ZBUD=y
+CONFIG_Z3FOLD=y
+CONFIG_ZSMALLOC=y
+CONFIG_PGTABLE_MAPPING=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_NR_CPUS=2
+CONFIG_HZ_100=y
+# CONFIG_SECCOMP is not set
+CONFIG_CROSS_COMPILE=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_DEFAULT_HOSTNAME="GRX500"
+CONFIG_SYSVIPC=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_RCU_EXPERT=y
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INITRAMFS_ROOT_UID=11609386
+CONFIG_INITRAMFS_ROOT_GID=2222
+# CONFIG_RD_GZIP is not set
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_INITRAMFS_COMPRESSION_XZ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_FHANDLE is not set
+# CONFIG_AIO is not set
+CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BLK_DEV_BSGLIB=y
+CONFIG_BLK_DEV_INTEGRITY=y
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_IPV6_SIT is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_ATM=m
+CONFIG_ATM_BR2684=m
+CONFIG_DMA_CMA=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+# CONFIG_VT_CONSOLE is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVMEM is not set
+CONFIG_SERIAL_LANTIQ=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+# CONFIG_HWMON is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_VIRTIO_MENU is not set
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_COMMON_CLK_INTEL=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXPORTFS_BLOCK_OPS=y
+# CONFIG_MANDATORY_FILE_LOCKING is not set
+CONFIG_QUOTA=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_AUTOFS4_FS=y
+CONFIG_FSCACHE=y
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_OBJECT_LIST=y
+CONFIG_CACHEFILES=y
+CONFIG_PROC_KCORE=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_PROC_CHILDREN=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZ4=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_NLS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_FRAME_WARN=2048
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_VM=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+# CONFIG_RCU_TRACE is not set
+CONFIG_LATENCYTOP=y
+# CONFIG_FTRACE is not set
+CONFIG_ATOMIC64_SELFTEST=y
+CONFIG_TEST_KSTRTOX=y
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_CRYPTO_CCM=y
+CONFIG_CRYPTO_GCM=y
+# CONFIG_CRYPTO_ECHAINIV is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_LIBCRC32C=y
+CONFIG_IRQ_POLL=y
diff --git a/arch/mips/include/asm/mach-intel-mips/cpu-feature-overrides.h b/arch/mips/include/asm/mach-intel-mips/cpu-feature-overrides.h
new file mode 100644
index 000000000000..ac5f3b943d2a
--- /dev/null
+++ b/arch/mips/include/asm/mach-intel-mips/cpu-feature-overrides.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file was derived from: include/asm-mips/cpu-features.h
+ *	Copyright (C) 2003, 2004 Ralf Baechle
+ *	Copyright (C) 2004 Maciej W. Rozycki
+ *	Copyright (C) 2018 Intel Corporation.
+ */
+
+#ifndef __ASM_MACH_INTEL_MIPS_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_INTEL_MIPS_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_tlb		1
+#define cpu_has_4kex		1
+#define cpu_has_3k_cache	0
+#define cpu_has_4k_cache	1
+#define cpu_has_tx39_cache	0
+#define cpu_has_sb1_cache	0
+#define cpu_has_fpu		0
+#define cpu_has_32fpr		0
+#define cpu_has_counter		1
+#define cpu_has_watch		1
+#define cpu_has_divec		1
+
+#define cpu_has_prefetch	1
+#define cpu_has_ejtag		1
+#define cpu_has_llsc		1
+
+#define cpu_has_mips16		0
+#define cpu_has_mdmx		0
+#define cpu_has_mips3d		0
+#define cpu_has_smartmips	0
+#define cpu_has_mmips		0
+#define cpu_has_vz		0
+
+#define cpu_has_mips32r1	1
+#define cpu_has_mips32r2	1
+#define cpu_has_mips64r1	0
+#define cpu_has_mips64r2	0
+
+#define cpu_has_dsp		1
+#define cpu_has_dsp2		0
+#define cpu_has_mipsmt		1
+
+#define cpu_has_vint		1
+#define cpu_has_veic		0
+
+#define cpu_has_64bits		0
+#define cpu_has_64bit_zero_reg	0
+#define cpu_has_64bit_gp_regs	0
+#define cpu_has_64bit_addresses	0
+
+#define cpu_has_cm2		1
+#define cpu_has_cm2_l2sync	1
+#define cpu_has_eva		1
+#define cpu_has_tlbinv		1
+
+#define cpu_dcache_line_size()	32
+#define cpu_icache_line_size()	32
+#define cpu_scache_line_size()	32
+
+#endif /* __ASM_MACH_INTEL_MIPS_CPU_FEATURE_OVERRIDES_H */
diff --git a/arch/mips/include/asm/mach-intel-mips/ioremap.h b/arch/mips/include/asm/mach-intel-mips/ioremap.h
new file mode 100644
index 000000000000..99b20ed0b457
--- /dev/null
+++ b/arch/mips/include/asm/mach-intel-mips/ioremap.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (C) 2014 Lei Chuanhua <Chuanhua.lei@lantiq.com>
+ *  Copyright (C) 2018 Intel Corporation.
+ */
+#ifndef __ASM_MACH_INTEL_MIPS_IOREMAP_H
+#define __ASM_MACH_INTEL_MIPS_IOREMAP_H
+
+#include <linux/types.h>
+
+static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr,
+					     phys_addr_t size)
+{
+	return phys_addr;
+}
+
+/*
+ * TOP IO Space definition for SSX7 components /PCIe/ToE/Memcpy
+ * physical 0xa0000000 --> virtual 0xe0000000
+ */
+#define GRX500_TOP_IOREMAP_BASE			0xA0000000
+#define GRX500_TOP_IOREMAP_SIZE			0x20000000
+#define GRX500_TOP_IOREMAP_PHYS_VIRT_OFFSET	0x40000000
+
+static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size,
+					 unsigned long flags)
+{
+	if (offset >= GRX500_TOP_IOREMAP_BASE &&
+	    offset < (GRX500_TOP_IOREMAP_BASE + GRX500_TOP_IOREMAP_SIZE))
+		return (void __iomem *)(unsigned long)
+			(offset + GRX500_TOP_IOREMAP_PHYS_VIRT_OFFSET);
+	return NULL;
+}
+
+static inline int plat_iounmap(const volatile void __iomem *addr)
+{
+	return (unsigned long)addr >= (unsigned long)GRX500_TOP_IOREMAP_BASE;
+}
+#endif /* __ASM_MACH_INTEL_MIPS_IOREMAP_H */
diff --git a/arch/mips/include/asm/mach-intel-mips/irq.h b/arch/mips/include/asm/mach-intel-mips/irq.h
new file mode 100644
index 000000000000..12a949084856
--- /dev/null
+++ b/arch/mips/include/asm/mach-intel-mips/irq.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (C) 2014 Lei Chuanhua <Chuanhua.lei@lantiq.com>
+ *  Copyright (C) 2018 Intel Corporation.
+ */
+
+#ifndef __INTEL_MIPS_IRQ_H
+#define __INTEL_MIPS_IRQ_H
+
+#define MIPS_CPU_IRQ_BASE	0
+#define MIPS_GIC_IRQ_BASE	(MIPS_CPU_IRQ_BASE + 8)
+
+#define NR_IRQS 256
+
+#include_next <irq.h>
+
+#endif /* __INTEL_MIPS_IRQ_H */
diff --git a/arch/mips/include/asm/mach-intel-mips/kernel-entry-init.h b/arch/mips/include/asm/mach-intel-mips/kernel-entry-init.h
new file mode 100644
index 000000000000..3893855b60c6
--- /dev/null
+++ b/arch/mips/include/asm/mach-intel-mips/kernel-entry-init.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Chris Dearman (chris@mips.com)
+ * Leonid Yegoshin (yegoshin@mips.com)
+ * Copyright (C) 2012 Mips Technologies, Inc.
+ * Copyright (C) 2018 Intel Corporation.
+ */
+#ifndef __ASM_MACH_INTEL_MIPS_KERNEL_ENTRY_INIT_H
+#define __ASM_MACH_INTEL_MIPS_KERNEL_ENTRY_INIT_H
+
+	.macro  platform_eva_init
+
+	.set    push
+	.set    reorder
+	/*
+	 * Get Config.K0 value and use it to program
+	 * the segmentation registers
+	 */
+	mfc0    t1, CP0_CONFIG
+	andi    t1, 0x7 /* CCA */
+	move    t2, t1
+	ins     t2, t1, 16, 3
+	/* SegCtl0 */
+	li      t0, ((MIPS_SEGCFG_UK << MIPS_SEGCFG_AM_SHIFT) |              \
+		(5 << MIPS_SEGCFG_PA_SHIFT) | (2 << MIPS_SEGCFG_C_SHIFT) |   \
+		(1 << MIPS_SEGCFG_EU_SHIFT)) |                               \
+		(((MIPS_SEGCFG_MSK << MIPS_SEGCFG_AM_SHIFT) |                \
+		(0 << MIPS_SEGCFG_PA_SHIFT) |                                \
+		(1 << MIPS_SEGCFG_EU_SHIFT)) << 16)
+	ins     t0, t1, 16, 3
+	mtc0    t0, $5, 2
+
+	/* SegCtl1 */
+	li      t0, ((MIPS_SEGCFG_UK << MIPS_SEGCFG_AM_SHIFT) |              \
+		(1 << MIPS_SEGCFG_PA_SHIFT) | (2 << MIPS_SEGCFG_C_SHIFT) |   \
+		(1 << MIPS_SEGCFG_EU_SHIFT)) |                               \
+		(((MIPS_SEGCFG_UK << MIPS_SEGCFG_AM_SHIFT) |                 \
+		(2 << MIPS_SEGCFG_PA_SHIFT) |                                \
+		(1 << MIPS_SEGCFG_EU_SHIFT)) << 16)
+	ins     t0, t1, 16, 3
+	mtc0    t0, $5, 3
+
+	/* SegCtl2 */
+	li      t0, ((MIPS_SEGCFG_MUSUK << MIPS_SEGCFG_AM_SHIFT) |           \
+		(0 << MIPS_SEGCFG_PA_SHIFT) |                                \
+		(1 << MIPS_SEGCFG_EU_SHIFT)) |                               \
+		(((MIPS_SEGCFG_MUSK << MIPS_SEGCFG_AM_SHIFT) |               \
+		(0 << MIPS_SEGCFG_PA_SHIFT)/*| (2 << MIPS_SEGCFG_C_SHIFT)*/ | \
+		(1 << MIPS_SEGCFG_EU_SHIFT)) << 16)
+	ins     t0, t1, 0, 3
+	mtc0    t0, $5, 4
+
+	jal     mips_ihb
+	mfc0    t0, $16, 5
+	li      t2, 0x40000000      /* K bit */
+	or      t0, t0, t2
+	mtc0    t0, $16, 5
+	sync
+	jal     mips_ihb
+
+	.set    pop
+	.endm
+
+	.macro	kernel_entry_setup
+	sync
+	ehb
+	platform_eva_init
+	.endm
+
+	.macro	smp_slave_setup
+	sync
+	ehb
+	platform_eva_init
+	.endm
+
+#endif /* __ASM_MACH_INTEL_MIPS_KERNEL_ENTRY_INIT_H */
diff --git a/arch/mips/include/asm/mach-intel-mips/spaces.h b/arch/mips/include/asm/mach-intel-mips/spaces.h
new file mode 100644
index 000000000000..abce53a65157
--- /dev/null
+++ b/arch/mips/include/asm/mach-intel-mips/spaces.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Author: Leonid Yegoshin (yegoshin@mips.com)
+ * Copyright (C) 2012 MIPS Technologies, Inc.
+ * Copyright (C) 2014 Lei Chuanhua <Chuanhua.lei@lantiq.com>
+ * Copyright (C) 2018 Intel Corporation.
+ */
+
+#ifndef _ASM_INTEL_MIPS_SPACES_H
+#define _ASM_INTEL_MIPS_SPACES_H
+
+#include <linux/sizes.h>
+
+#define PAGE_OFFSET		_AC(0x60000000, UL)
+#define PHYS_OFFSET		_AC(0x20000000, UL)
+
+/* No Highmem Support */
+#define HIGHMEM_START		_AC(0xffff0000, UL)
+
+#define FIXADDR_TOP		((unsigned long)(long)(int)0xcffe0000)
+
+#define IO_SIZE			_AC(0x10000000, UL)
+#define IO_SHIFT		_AC(0x10000000, UL)
+
+/* IO space one */
+#define __pa_symbol(x)		__pa(x)
+
+#include <asm/mach-generic/spaces.h>
+#endif /* __ASM_INTEL_MIPS_SPACES_H */
diff --git a/arch/mips/include/asm/mach-intel-mips/war.h b/arch/mips/include/asm/mach-intel-mips/war.h
new file mode 100644
index 000000000000..1c95553151e1
--- /dev/null
+++ b/arch/mips/include/asm/mach-intel-mips/war.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_MIPS_MACH_INTEL_MIPS_WAR_H
+#define __ASM_MIPS_MACH_INTEL_MIPS_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR	0
+#define R4600_V1_HIT_CACHEOP_WAR	0
+#define R4600_V2_HIT_CACHEOP_WAR	0
+#define R5432_CP0_INTERRUPT_WAR		0
+#define BCM1250_M3_WAR			0
+#define SIBYTE_1956_WAR			0
+#define MIPS4K_ICACHE_REFILL_WAR	0
+#define MIPS_CACHE_SYNC_WAR		0
+#define TX49XX_ICACHE_INDEX_INV_WAR	0
+#define ICACHE_REFILLS_WORKAROUND_WAR	0
+#define R10000_LLSC_WAR			0
+#define MIPS34K_MISSED_ITLB_WAR		0
+
+#endif /* __ASM_MIPS_MACH_INTEL_MIPS_WAR_H */
diff --git a/arch/mips/intel-mips/Kconfig b/arch/mips/intel-mips/Kconfig
new file mode 100644
index 000000000000..35d2ae2b5408
--- /dev/null
+++ b/arch/mips/intel-mips/Kconfig
@@ -0,0 +1,22 @@
+if INTEL_MIPS
+
+choice
+	prompt "Built-in device tree"
+	help
+	  Legacy bootloaders do not pass a DTB pointer to the kernel, so
+	  if a "wrapper" is not being used, the kernel will need to include
+	  a device tree that matches the target board.
+
+	  The builtin DTB will only be used if the firmware does not supply
+	  a valid DTB.
+
+config DTB_INTEL_MIPS_NONE
+	bool "None"
+
+config DTB_INTEL_MIPS_GRX500
+	bool "Intel MIPS GRX500 Board"
+	select BUILTIN_DTB
+
+endchoice
+
+endif
diff --git a/arch/mips/intel-mips/Makefile b/arch/mips/intel-mips/Makefile
new file mode 100644
index 000000000000..9f272d06eecd
--- /dev/null
+++ b/arch/mips/intel-mips/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_INTEL_MIPS)	+= prom.o irq.o time.o
diff --git a/arch/mips/intel-mips/Platform b/arch/mips/intel-mips/Platform
new file mode 100644
index 000000000000..b34750eeaeb0
--- /dev/null
+++ b/arch/mips/intel-mips/Platform
@@ -0,0 +1,11 @@
+#
+# MIPs SoC platform
+#
+
+platform-$(CONFIG_INTEL_MIPS)			+= intel-mips/
+cflags-$(CONFIG_INTEL_MIPS)			+= -I$(srctree)/arch/mips/include/asm/mach-intel-mips
+ifdef CONFIG_EVA
+	load-$(CONFIG_INTEL_MIPS)		= 0xffffffff60020000
+else
+	load-$(CONFIG_INTEL_MIPS)		= 0xffffffff80020000
+endif
diff --git a/arch/mips/intel-mips/irq.c b/arch/mips/intel-mips/irq.c
new file mode 100644
index 000000000000..00637a5cdd20
--- /dev/null
+++ b/arch/mips/intel-mips/irq.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016 Intel Corporation.
+ */
+#include <linux/init.h>
+#include <linux/irqchip.h>
+#include <linux/of_irq.h>
+#include <asm/irq.h>
+
+#include <asm/irq_cpu.h>
+
+void __init arch_init_irq(void)
+{
+	struct device_node *intc_node;
+
+	pr_info("EIC is %s\n", cpu_has_veic ? "on" : "off");
+	pr_info("VINT is %s\n", cpu_has_vint ? "on" : "off");
+
+	intc_node = of_find_compatible_node(NULL, NULL,
+					    "mti,cpu-interrupt-controller");
+	if (!cpu_has_veic && !intc_node)
+		mips_cpu_irq_init();
+
+	irqchip_init();
+}
+
+int get_c0_perfcount_int(void)
+{
+	return gic_get_c0_perfcount_int();
+}
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
+
+unsigned int get_c0_compare_int(void)
+{
+	return gic_get_c0_compare_int();
+}
diff --git a/arch/mips/intel-mips/prom.c b/arch/mips/intel-mips/prom.c
new file mode 100644
index 000000000000..9407858ddc94
--- /dev/null
+++ b/arch/mips/intel-mips/prom.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2014 Lei Chuanhua <Chuanhua.lei@lantiq.com>
+ * Copyright (C) 2016 Intel Corporation.
+ */
+#include <linux/init.h>
+#include <linux/export.h>
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <asm/mips-cps.h>
+#include <asm/smp-ops.h>
+#include <asm/dma-coherence.h>
+#include <asm/prom.h>
+
+#define IOPORT_RESOURCE_START   0x10000000
+#define IOPORT_RESOURCE_END     0xffffffff
+#define IOMEM_RESOURCE_START    0x10000000
+#define IOMEM_RESOURCE_END      0xffffffff
+
+const char *get_system_type(void)
+{
+	return "Intel MIPS interAptiv SoC";
+}
+
+void prom_free_prom_memory(void)
+{
+}
+
+static void __init prom_init_cmdline(void)
+{
+	int i;
+	int argc;
+	char **argv;
+
+	/*
+	 * If u-boot pass parameters, it is ok, however, if without u-boot
+	 * JTAG or other tool has to reset all register value before it goes
+	 * emulation most likely belongs to this category
+	 */
+	if (fw_arg0 == 0 || fw_arg1 == 0)
+		return;
+
+	argc = fw_arg0;
+	argv = (char **)KSEG1ADDR(fw_arg1);
+
+	arcs_cmdline[0] = '\0';
+
+	for (i = 0; i < argc; i++) {
+		char *p = (char *)KSEG1ADDR(argv[i]);
+
+		if (argv[i] && *p) {
+			strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
+			strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+		}
+	}
+}
+
+static int __init plat_enable_iocoherency(void)
+{
+	int supported = 0;
+
+	if (mips_cps_numiocu(0) != 0) {
+		/* Nothing special needs to be done to enable coherency */
+		pr_info("Coherence Manager IOCU detected\n");
+		/* Second IOCU for MPE or other master access register */
+		write_gcr_reg0_base(0xa0000000);
+		write_gcr_reg0_mask(0xf8000000 | CM_GCR_REGn_MASK_CMTGT_IOCU1);
+		supported = 1;
+	}
+
+	/* hw_coherentio = supported; */
+
+	return supported;
+}
+
+static void __init plat_setup_iocoherency(void)
+{
+#ifdef CONFIG_DMA_NONCOHERENT
+	/*
+	 * Kernel has been configured with software coherency
+	 * but we might choose to turn it off and use hardware
+	 * coherency instead.
+	 */
+	if (plat_enable_iocoherency()) {
+		if (coherentio == IO_COHERENCE_DISABLED)
+			pr_info("Hardware DMA cache coherency disabled\n");
+		else
+			pr_info("Hardware DMA cache coherency enabled\n");
+	} else {
+		if (coherentio == IO_COHERENCE_ENABLED)
+			pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n");
+		else
+			pr_info("Software DMA cache coherency enabled\n");
+	}
+#else
+	if (!plat_enable_iocoherency())
+		panic("Hardware DMA cache coherency not supported!");
+#endif
+}
+
+static void free_init_pages_eva_intel(void *begin, void *end)
+{
+	free_init_pages("unused kernel", __pa_symbol((unsigned long *)begin),
+			__pa_symbol((unsigned long *)end));
+}
+
+static void plat_early_init_devtree(void)
+{
+	void *dtb;
+
+	/*
+	 * Load the builtin devicetree. This causes the chosen node to be
+	 * parsed resulting in our memory appearing
+	 */
+	if (fw_passed_dtb) /* used by CONFIG_MIPS_APPENDED_RAW_DTB as well */
+		dtb = (void *)fw_passed_dtb;
+	else if (__dtb_start != __dtb_end)
+		dtb = (void *)__dtb_start;
+
+	if (dtb)
+		__dt_setup_arch(dtb);
+}
+
+void __init plat_mem_setup(void)
+{
+	ioport_resource.start = IOPORT_RESOURCE_START;
+	ioport_resource.end = ~0UL; /* No limit */
+	iomem_resource.start = IOMEM_RESOURCE_START;
+	iomem_resource.end = ~0UL; /* No limit */
+
+	set_io_port_base((unsigned long)KSEG1);
+
+	strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+
+	plat_early_init_devtree();
+	plat_setup_iocoherency();
+
+	if (IS_ENABLED(CONFIG_EVA))
+		free_init_pages_eva = free_init_pages_eva_intel;
+	else
+		free_init_pages_eva = 0;
+}
+
+void __init device_tree_init(void)
+{
+	if (!initial_boot_params)
+		return;
+
+	unflatten_and_copy_device_tree();
+}
+
+#define CPC_BASE_ADDR		0x12310000
+
+phys_addr_t mips_cpc_default_phys_base(void)
+{
+	return CPC_BASE_ADDR;
+}
+
+void __init prom_init(void)
+{
+	prom_init_cmdline();
+
+	mips_cpc_probe();
+
+	if (!register_cps_smp_ops())
+		return;
+
+	if (!register_cmp_smp_ops())
+		return;
+
+	if (!register_vsmp_smp_ops())
+		return;
+}
+
+static int __init plat_publish_devices(void)
+{
+	if (!of_have_populated_dt())
+		return 0;
+	return of_platform_populate(NULL, of_default_bus_match_table, NULL,
+				    NULL);
+}
+arch_initcall(plat_publish_devices);
diff --git a/arch/mips/intel-mips/time.c b/arch/mips/intel-mips/time.c
new file mode 100644
index 000000000000..77ad4014fe9d
--- /dev/null
+++ b/arch/mips/intel-mips/time.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016 Intel Corporation.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/of.h>
+
+#include <asm/time.h>
+
+static inline u32 get_counter_resolution(void)
+{
+	u32 res;
+
+	__asm__ __volatile__(".set	push\n"
+			     ".set	mips32r2\n"
+			     "rdhwr	%0, $3\n"
+			     ".set pop\n"
+			     : "=&r" (res)
+			     : /* no input */
+			     : "memory");
+
+	return res;
+}
+
+void __init plat_time_init(void)
+{
+	unsigned long cpuclk;
+	struct device_node *np;
+	struct clk *clk;
+
+	of_clk_init(NULL);
+
+	np = of_get_cpu_node(0, NULL);
+	if (!np) {
+		pr_err("Failed to get CPU node\n");
+		return;
+	}
+
+	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk)) {
+		pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk));
+		return;
+	}
+
+	cpuclk = clk_get_rate(clk);
+	mips_hpt_frequency = cpuclk / get_counter_resolution();
+	clk_put(clk);
+
+	write_c0_compare(read_c0_count());
+	pr_info("CPU Clock: %ldHz  mips_hpt_frequency %dHz\n",
+		cpuclk, mips_hpt_frequency);
+	timer_probe();
+}
-- 
2.11.0

^ permalink raw reply related

* [PATCH 4/7] tty: serial: lantiq: Always use readl()/writel()
From: Songjun Wu @ 2018-06-12  5:40 UTC (permalink / raw)
  To: hua.ma, yixin.zhu, chuanhua.lei
  Cc: linux-mips, qi-ming.wu, linux-clk, linux-serial, devicetree,
	Songjun Wu, James Hogan, Jiri Slaby, linux-kernel,
	Greg Kroah-Hartman, Ralf Baechle
In-Reply-To: <20180612054034.4969-1-songjun.wu@linux.intel.com>

Previous implementation uses platform-dependent functions
ltq_w32()/ltq_r32() to access registers. Those functions are not
available for other SoC which uses the same IP.
Change to OS provided readl()/writel() and readb()/writeb(), so
that different SoCs can use the same driver.

Signed-off-by: Songjun Wu <songjun.wu@linux.intel.com>
---

 arch/mips/Kconfig           |   1 -
 drivers/tty/serial/lantiq.c | 236 ++++++++++++++++++++++++--------------------
 2 files changed, 128 insertions(+), 109 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index c82cebeb6192..7bae259edd0b 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -395,7 +395,6 @@ config LANTIQ
 	select SYS_SUPPORTS_VPE_LOADER
 	select SYS_HAS_EARLY_PRINTK
 	select GPIOLIB
-	select SWAP_IO_SPACE
 	select BOOT_RAW
 	select CLKDEV_LOOKUP
 	select USE_OF
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 044128277248..1127586dbc94 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -49,7 +49,8 @@
 #define LTQ_ASC_RXFCON		0x0040
 #define LTQ_ASC_CON		0x0010
 #define LTQ_ASC_BG		0x0050
-#define LTQ_ASC_IRNREN		0x00F4
+#define LTQ_ASC_FDV		0x0058
+#define LTQ_ASC_IRNEN		0x00F4
 
 #define ASC_IRNREN_TX		0x1
 #define ASC_IRNREN_RX		0x2
@@ -62,6 +63,7 @@
 #define ASCOPT_CSIZE		0x3
 #define TXFIFO_FL		1
 #define RXFIFO_FL		1
+#define ASCCLC_DISR		0x1
 #define ASCCLC_DISS		0x2
 #define ASCCLC_RMCMASK		0x0000FF00
 #define ASCCLC_RMCOFFSET	8
@@ -84,6 +86,7 @@
 #define ASCWHBSTATE_CLRPE	0x00000004
 #define ASCWHBSTATE_CLRFE	0x00000008
 #define ASCWHBSTATE_CLRROE	0x00000020
+#define ASCWHBSTATE_CLRALL	0x000000FC
 #define ASCTXFCON_TXFEN		0x0001
 #define ASCTXFCON_TXFFLU	0x0002
 #define ASCTXFCON_TXFITLMASK	0x3F00
@@ -97,6 +100,10 @@
 #define ASCFSTAT_TXFREEMASK	0x3F000000
 #define ASCFSTAT_TXFREEOFF	24
 
+#define asc_w32_mask(clear, set, reg)	\
+	({ typeof(reg) reg_ = (reg);	\
+	writel((readl(reg_) & ~(clear)) | (set), reg_); })
+
 static void lqasc_tx_chars(struct uart_port *port);
 static struct ltq_uart_port *lqasc_port[MAXPORTS];
 static struct uart_driver lqasc_reg;
@@ -113,20 +120,17 @@ struct ltq_uart_port {
 	unsigned int		err_irq;
 };
 
-static inline struct
-ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
+static inline struct ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
 {
 	return container_of(port, struct ltq_uart_port, port);
 }
 
-static void
-lqasc_stop_tx(struct uart_port *port)
+static void lqasc_stop_tx(struct uart_port *port)
 {
 	return;
 }
 
-static void
-lqasc_start_tx(struct uart_port *port)
+static void lqasc_start_tx(struct uart_port *port)
 {
 	unsigned long flags;
 	spin_lock_irqsave(&ltq_asc_lock, flags);
@@ -135,23 +139,21 @@ lqasc_start_tx(struct uart_port *port)
 	return;
 }
 
-static void
-lqasc_stop_rx(struct uart_port *port)
+static void lqasc_stop_rx(struct uart_port *port)
 {
-	ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
+	writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
 }
 
-static int
-lqasc_rx_chars(struct uart_port *port)
+static int lqasc_rx_chars(struct uart_port *port)
 {
 	struct tty_port *tport = &port->state->port;
 	unsigned int ch = 0, rsr = 0, fifocnt;
 
-	fifocnt = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
+	fifocnt = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
 	while (fifocnt--) {
 		u8 flag = TTY_NORMAL;
-		ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
-		rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
+		ch = readb(port->membase + LTQ_ASC_RBUF);
+		rsr = (readl(port->membase + LTQ_ASC_STATE)
 			& ASCSTATE_ANY) | UART_DUMMY_UER_RX;
 		tty_flip_buffer_push(tport);
 		port->icount.rx++;
@@ -163,16 +165,16 @@ lqasc_rx_chars(struct uart_port *port)
 		if (rsr & ASCSTATE_ANY) {
 			if (rsr & ASCSTATE_PE) {
 				port->icount.parity++;
-				ltq_w32_mask(0, ASCWHBSTATE_CLRPE,
+				asc_w32_mask(0, ASCWHBSTATE_CLRPE,
 					port->membase + LTQ_ASC_WHBSTATE);
 			} else if (rsr & ASCSTATE_FE) {
 				port->icount.frame++;
-				ltq_w32_mask(0, ASCWHBSTATE_CLRFE,
+				asc_w32_mask(0, ASCWHBSTATE_CLRFE,
 					port->membase + LTQ_ASC_WHBSTATE);
 			}
 			if (rsr & ASCSTATE_ROE) {
 				port->icount.overrun++;
-				ltq_w32_mask(0, ASCWHBSTATE_CLRROE,
+				asc_w32_mask(0, ASCWHBSTATE_CLRROE,
 					port->membase + LTQ_ASC_WHBSTATE);
 			}
 
@@ -202,8 +204,7 @@ lqasc_rx_chars(struct uart_port *port)
 	return 0;
 }
 
-static void
-lqasc_tx_chars(struct uart_port *port)
+static void lqasc_tx_chars(struct uart_port *port)
 {
 	struct circ_buf *xmit = &port->state->xmit;
 	if (uart_tx_stopped(port)) {
@@ -211,10 +212,10 @@ lqasc_tx_chars(struct uart_port *port)
 		return;
 	}
 
-	while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) &
+	while (((readl(port->membase + LTQ_ASC_FSTAT) &
 		ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
 		if (port->x_char) {
-			ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF);
+			writeb(port->x_char, port->membase + LTQ_ASC_TBUF);
 			port->icount.tx++;
 			port->x_char = 0;
 			continue;
@@ -223,8 +224,8 @@ lqasc_tx_chars(struct uart_port *port)
 		if (uart_circ_empty(xmit))
 			break;
 
-		ltq_w8(port->state->xmit.buf[port->state->xmit.tail],
-			port->membase + LTQ_ASC_TBUF);
+		writeb(port->state->xmit.buf[port->state->xmit.tail],
+		       port->membase + LTQ_ASC_TBUF);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		port->icount.tx++;
 	}
@@ -233,48 +234,58 @@ lqasc_tx_chars(struct uart_port *port)
 		uart_write_wakeup(port);
 }
 
-static irqreturn_t
-lqasc_tx_int(int irq, void *_port)
+static irqreturn_t lqasc_tx_int(int irq, void *_port)
 {
 	unsigned long flags;
 	struct uart_port *port = (struct uart_port *)_port;
 	spin_lock_irqsave(&ltq_asc_lock, flags);
-	ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
+	writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
 	spin_unlock_irqrestore(&ltq_asc_lock, flags);
 	lqasc_start_tx(port);
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t
-lqasc_err_int(int irq, void *_port)
+static irqreturn_t lqasc_err_int(int irq, void *_port)
 {
 	unsigned long flags;
+	u32 stat;
 	struct uart_port *port = (struct uart_port *)_port;
+
 	spin_lock_irqsave(&ltq_asc_lock, flags);
 	/* clear any pending interrupts */
-	ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
-		ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
+	writel(ASC_IRNCR_EIR, port->membase + LTQ_ASC_IRNCR);
+	stat = readl(port->membase + LTQ_ASC_STATE);
+	if ((stat & ASCCON_ROEN)) {
+		asc_w32_mask(0, ASCRXFCON_RXFFLU,
+			     port->membase + LTQ_ASC_RXFCON);
+		port->icount.overrun++;
+	}
+	if (stat & ASCCON_TOEN) {
+		asc_w32_mask(0, ASCTXFCON_TXFFLU,
+			     port->membase + LTQ_ASC_TXFCON);
+		port->icount.overrun++;
+	}
+	asc_w32_mask(0, ASCWHBSTATE_CLRALL, port->membase + LTQ_ASC_WHBSTATE);
 	spin_unlock_irqrestore(&ltq_asc_lock, flags);
+
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t
-lqasc_rx_int(int irq, void *_port)
+static irqreturn_t lqasc_rx_int(int irq, void *_port)
 {
 	unsigned long flags;
 	struct uart_port *port = (struct uart_port *)_port;
 	spin_lock_irqsave(&ltq_asc_lock, flags);
-	ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
+	writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
 	lqasc_rx_chars(port);
 	spin_unlock_irqrestore(&ltq_asc_lock, flags);
 	return IRQ_HANDLED;
 }
 
-static unsigned int
-lqasc_tx_empty(struct uart_port *port)
+static unsigned int lqasc_tx_empty(struct uart_port *port)
 {
 	int status;
-	status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
+	status = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
 	return status ? 0 : TIOCSER_TEMT;
 }
 
@@ -284,8 +295,7 @@ lqasc_get_mctrl(struct uart_port *port)
 	return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR;
 }
 
-static void
-lqasc_set_mctrl(struct uart_port *port, u_int mctrl)
+static void lqasc_set_mctrl(struct uart_port *port, u_int mctrl)
 {
 }
 
@@ -304,48 +314,49 @@ lqasc_startup(struct uart_port *port)
 		clk_enable(ltq_port->clk);
 	port->uartclk = clk_get_rate(ltq_port->fpiclk);
 
-	ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
+	asc_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
 		port->membase + LTQ_ASC_CLC);
 
-	ltq_w32(0, port->membase + LTQ_ASC_PISEL);
-	ltq_w32(
-		((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
-		ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
-		port->membase + LTQ_ASC_TXFCON);
-	ltq_w32(
-		((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
-		| ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
-		port->membase + LTQ_ASC_RXFCON);
+	writel(0, port->membase + LTQ_ASC_PISEL);
+	writel(((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
+		 ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
+		 port->membase + LTQ_ASC_TXFCON);
+	writel(((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) |
+		 ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
+		 port->membase + LTQ_ASC_RXFCON);
 	/* make sure other settings are written to hardware before
 	 * setting enable bits
 	 */
 	wmb();
-	ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
-		ASCCON_ROEN, port->membase + LTQ_ASC_CON);
+	asc_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
+		     ASCCON_ROEN, port->membase + LTQ_ASC_CON);
 
 	retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
-		0, "asc_tx", port);
+			     0, "asc_tx", port);
 	if (retval) {
 		pr_err("failed to request lqasc_tx_int\n");
 		return retval;
 	}
 
 	retval = request_irq(ltq_port->rx_irq, lqasc_rx_int,
-		0, "asc_rx", port);
+			     0, "asc_rx", port);
 	if (retval) {
 		pr_err("failed to request lqasc_rx_int\n");
 		goto err1;
 	}
 
 	retval = request_irq(ltq_port->err_irq, lqasc_err_int,
-		0, "asc_err", port);
+			     0, "asc_err", port);
 	if (retval) {
 		pr_err("failed to request lqasc_err_int\n");
 		goto err2;
 	}
 
-	ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
-		port->membase + LTQ_ASC_IRNREN);
+	writel(ASC_IRNCR_RIR | ASC_IRNCR_EIR | ASC_IRNCR_TIR,
+	       port->membase + LTQ_ASC_IRNCR);
+	writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
+	       port->membase + LTQ_ASC_IRNEN);
+
 	return 0;
 
 err2:
@@ -355,26 +366,41 @@ lqasc_startup(struct uart_port *port)
 	return retval;
 }
 
-static void
-lqasc_shutdown(struct uart_port *port)
+static void lqasc_shutdown(struct uart_port *port)
 {
+	unsigned long flags;
 	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+	int i = 100;
+
+	writel(0, port->membase + LTQ_ASC_CON);
 	free_irq(ltq_port->tx_irq, port);
 	free_irq(ltq_port->rx_irq, port);
 	free_irq(ltq_port->err_irq, port);
 
-	ltq_w32(0, port->membase + LTQ_ASC_CON);
-	ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
-		port->membase + LTQ_ASC_RXFCON);
-	ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
-		port->membase + LTQ_ASC_TXFCON);
+	spin_lock_irqsave(&ltq_port->lock, flags);
+	/* TX/RX FIFO disable will flush TX/RX FIFO automatically */
+	asc_w32_mask(ASCRXFCON_RXFEN, 0, port->membase + LTQ_ASC_RXFCON);
+	asc_w32_mask(ASCTXFCON_TXFEN, 0, port->membase + LTQ_ASC_TXFCON);
+
+	/* Make sure flush is done, FIFO empty */
+	while ((readl(port->membase + LTQ_ASC_FSTAT) & (ASCFSTAT_RXFFLMASK |
+		ASCFSTAT_TXFFLMASK)) && i--)
+		;
+
+	/*
+	 * Clock off it, TX/RX free FIFO will be always one byte
+	 * Console TX free FIFO check will always pass
+	 */
+	asc_w32_mask(ASCCLC_DISR | ASCCLC_RMCMASK, 0,
+		     port->membase + LTQ_ASC_CLC);
+	spin_unlock_irqrestore(&ltq_port->lock, flags);
+
 	if (!IS_ERR(ltq_port->clk))
 		clk_disable(ltq_port->clk);
 }
 
-static void
-lqasc_set_termios(struct uart_port *port,
-	struct ktermios *new, struct ktermios *old)
+static void lqasc_set_termios(struct uart_port *port,
+			      struct ktermios *new, struct ktermios *old)
 {
 	unsigned int cflag;
 	unsigned int iflag;
@@ -382,6 +408,8 @@ lqasc_set_termios(struct uart_port *port,
 	unsigned int baud;
 	unsigned int con = 0;
 	unsigned long flags;
+	u32 fdv = 0;
+	u32 reload = 0;
 
 	cflag = new->c_cflag;
 	iflag = new->c_iflag;
@@ -394,7 +422,7 @@ lqasc_set_termios(struct uart_port *port,
 	case CS5:
 	case CS6:
 	default:
-		new->c_cflag &= ~ CSIZE;
+		new->c_cflag &= ~CSIZE;
 		new->c_cflag |= CS8;
 		con = ASCCON_M_8ASYNC;
 		break;
@@ -438,30 +466,29 @@ lqasc_set_termios(struct uart_port *port,
 	spin_lock_irqsave(&ltq_asc_lock, flags);
 
 	/* set up CON */
-	ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON);
+	asc_w32_mask(0, con, port->membase + LTQ_ASC_CON);
 
 	/* Set baud rate - take a divider of 2 into account */
 	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
 	divisor = uart_get_divisor(port, baud);
 	divisor = divisor / 2 - 1;
 
-	/* disable the baudrate generator */
-	ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
-
-	/* make sure the fractional divider is off */
-	ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
-
-	/* set up to use divisor of 2 */
-	ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
+	asc_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
+	/* Ensure the setting is effect before enabling */
+	wmb();
+	/* make sure the fractional divider is enabled */
+	asc_w32_mask(0, ASCCON_FDE, port->membase + LTQ_ASC_CON);
 
 	/* now we can write the new baudrate into the register */
-	ltq_w32(divisor, port->membase + LTQ_ASC_BG);
+	writel(reload, port->membase + LTQ_ASC_BG);
+	/* now we can write the new baudrate into the register */
+	writel(fdv, port->membase + LTQ_ASC_FDV);
 
 	/* turn the baudrate generator back on */
-	ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
+	asc_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
 
 	/* enable rx */
-	ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
+	writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
 
 	spin_unlock_irqrestore(&ltq_asc_lock, flags);
 
@@ -472,8 +499,7 @@ lqasc_set_termios(struct uart_port *port,
 	uart_update_timeout(port, cflag, baud);
 }
 
-static const char*
-lqasc_type(struct uart_port *port)
+static const char *lqasc_type(struct uart_port *port)
 {
 	if (port->type == PORT_LTQ_ASC)
 		return DRVNAME;
@@ -481,8 +507,7 @@ lqasc_type(struct uart_port *port)
 		return NULL;
 }
 
-static void
-lqasc_release_port(struct uart_port *port)
+static void lqasc_release_port(struct uart_port *port)
 {
 	struct platform_device *pdev = to_platform_device(port->dev);
 
@@ -492,8 +517,7 @@ lqasc_release_port(struct uart_port *port)
 	}
 }
 
-static int
-lqasc_request_port(struct uart_port *port)
+static int lqasc_request_port(struct uart_port *port)
 {
 	struct platform_device *pdev = to_platform_device(port->dev);
 	struct resource *res;
@@ -507,7 +531,7 @@ lqasc_request_port(struct uart_port *port)
 	size = resource_size(res);
 
 	res = devm_request_mem_region(&pdev->dev, res->start,
-		size, dev_name(&pdev->dev));
+				      size, dev_name(&pdev->dev));
 	if (!res) {
 		dev_err(&pdev->dev, "cannot request I/O memory region");
 		return -EBUSY;
@@ -515,15 +539,14 @@ lqasc_request_port(struct uart_port *port)
 
 	if (port->flags & UPF_IOREMAP) {
 		port->membase = devm_ioremap_nocache(&pdev->dev,
-			port->mapbase, size);
+						     port->mapbase, size);
 		if (port->membase == NULL)
 			return -ENOMEM;
 	}
 	return 0;
 }
 
-static void
-lqasc_config_port(struct uart_port *port, int flags)
+static void lqasc_config_port(struct uart_port *port, int flags)
 {
 	if (flags & UART_CONFIG_TYPE) {
 		port->type = PORT_LTQ_ASC;
@@ -531,17 +554,17 @@ lqasc_config_port(struct uart_port *port, int flags)
 	}
 }
 
-static int
-lqasc_verify_port(struct uart_port *port,
-	struct serial_struct *ser)
+static int lqasc_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
 	int ret = 0;
+
 	if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC)
 		ret = -EINVAL;
 	if (ser->irq < 0 || ser->irq >= NR_IRQS)
 		ret = -EINVAL;
 	if (ser->baud_base < 9600)
 		ret = -EINVAL;
+
 	return ret;
 }
 
@@ -563,8 +586,7 @@ static const struct uart_ops lqasc_pops = {
 	.verify_port =	lqasc_verify_port,
 };
 
-static void
-lqasc_console_putchar(struct uart_port *port, int ch)
+static void lqasc_console_putchar(struct uart_port *port, int ch)
 {
 	int fifofree;
 
@@ -572,10 +594,11 @@ lqasc_console_putchar(struct uart_port *port, int ch)
 		return;
 
 	do {
-		fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT)
+		fifofree = (readl(port->membase + LTQ_ASC_FSTAT)
 			& ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
 	} while (fifofree == 0);
-	ltq_w8(ch, port->membase + LTQ_ASC_TBUF);
+
+	writeb(ch, port->membase + LTQ_ASC_TBUF);
 }
 
 static void lqasc_serial_port_write(struct uart_port *port, const char *s,
@@ -588,8 +611,7 @@ static void lqasc_serial_port_write(struct uart_port *port, const char *s,
 	spin_unlock_irqrestore(&ltq_asc_lock, flags);
 }
 
-static void
-lqasc_console_write(struct console *co, const char *s, u_int count)
+static void lqasc_console_write(struct console *co, const char *s, u_int count)
 {
 	struct ltq_uart_port *ltq_port;
 
@@ -603,8 +625,7 @@ lqasc_console_write(struct console *co, const char *s, u_int count)
 	lqasc_serial_port_write(&ltq_port->port, s, count);
 }
 
-static int __init
-lqasc_console_setup(struct console *co, char *options)
+static int __init lqasc_console_setup(struct console *co, char *options)
 {
 	struct ltq_uart_port *ltq_port;
 	struct uart_port *port;
@@ -629,6 +650,7 @@ lqasc_console_setup(struct console *co, char *options)
 
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
 	return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
@@ -642,8 +664,7 @@ static struct console lqasc_console = {
 	.data =		&lqasc_reg,
 };
 
-static int __init
-lqasc_console_init(void)
+static int __init lqasc_console_init(void)
 {
 	register_console(&lqasc_console);
 	return 0;
@@ -667,6 +688,7 @@ lqasc_serial_early_console_setup(struct earlycon_device *device,
 		return -ENODEV;
 
 	device->con->write = lqasc_serial_early_console_write;
+
 	return 0;
 }
 OF_EARLYCON_DECLARE(lantiq, DRVNAME, lqasc_serial_early_console_setup);
@@ -681,8 +703,7 @@ static struct uart_driver lqasc_reg = {
 	.cons =		&lqasc_console,
 };
 
-static int __init
-lqasc_probe(struct platform_device *pdev)
+static int __init lqasc_probe(struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node;
 	struct ltq_uart_port *ltq_port;
@@ -693,7 +714,7 @@ lqasc_probe(struct platform_device *pdev)
 
 	mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	ret = of_irq_to_resource_table(node, irqres, 3);
-	if (!mmres || (ret != 3)) {
+	if (!mmres || ret != 3) {
 		dev_err(&pdev->dev,
 			"failed to get memory/irq for serial port\n");
 		return -ENODEV;
@@ -709,7 +730,7 @@ lqasc_probe(struct platform_device *pdev)
 	}
 
 	ltq_port = devm_kzalloc(&pdev->dev, sizeof(struct ltq_uart_port),
-			GFP_KERNEL);
+				GFP_KERNEL);
 	if (!ltq_port)
 		return -ENOMEM;
 
@@ -759,8 +780,7 @@ static struct platform_driver lqasc_driver = {
 	},
 };
 
-int __init
-init_lqasc(void)
+int __init init_lqasc(void)
 {
 	int ret;
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH 5/7] tty: serial: lantiq: Convert global lock to per device lock
From: Songjun Wu @ 2018-06-12  5:40 UTC (permalink / raw)
  To: hua.ma, yixin.zhu, chuanhua.lei
  Cc: linux-mips, qi-ming.wu, linux-clk, linux-serial, devicetree,
	Songjun Wu, Greg Kroah-Hartman, linux-kernel, Jiri Slaby
In-Reply-To: <20180612054034.4969-1-songjun.wu@linux.intel.com>

Previous implementation uses one global lock to protect the resource.
If the serial driver have multiple entries, this kind of lock will
slow down the performance.
Add the lock at device level. This will lock only when the function
calling only to the same device.
So that it can avoid useless lock protection.

Signed-off-by: Songjun Wu <songjun.wu@linux.intel.com>
---

 drivers/tty/serial/lantiq.c | 51 ++++++++++++++++++++++++++++++---------------
 1 file changed, 34 insertions(+), 17 deletions(-)

diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 1127586dbc94..72aab1b05265 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -107,7 +107,6 @@
 static void lqasc_tx_chars(struct uart_port *port);
 static struct ltq_uart_port *lqasc_port[MAXPORTS];
 static struct uart_driver lqasc_reg;
-static DEFINE_SPINLOCK(ltq_asc_lock);
 
 struct ltq_uart_port {
 	struct uart_port	port;
@@ -118,6 +117,7 @@ struct ltq_uart_port {
 	unsigned int		tx_irq;
 	unsigned int		rx_irq;
 	unsigned int		err_irq;
+	spinlock_t		lock;  /* exclusive access for multi core */
 };
 
 static inline struct ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
@@ -133,10 +133,11 @@ static void lqasc_stop_tx(struct uart_port *port)
 static void lqasc_start_tx(struct uart_port *port)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&ltq_asc_lock, flags);
+	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+
+	spin_lock_irqsave(&ltq_port->lock, flags);
 	lqasc_tx_chars(port);
-	spin_unlock_irqrestore(&ltq_asc_lock, flags);
-	return;
+	spin_unlock_irqrestore(&ltq_port->lock, flags);
 }
 
 static void lqasc_stop_rx(struct uart_port *port)
@@ -238,10 +239,14 @@ static irqreturn_t lqasc_tx_int(int irq, void *_port)
 {
 	unsigned long flags;
 	struct uart_port *port = (struct uart_port *)_port;
-	spin_lock_irqsave(&ltq_asc_lock, flags);
+	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+
+	spin_lock_irqsave(&ltq_port->lock, flags);
 	writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
-	spin_unlock_irqrestore(&ltq_asc_lock, flags);
+	spin_unlock_irqrestore(&ltq_port->lock, flags);
+
 	lqasc_start_tx(port);
+
 	return IRQ_HANDLED;
 }
 
@@ -250,8 +255,9 @@ static irqreturn_t lqasc_err_int(int irq, void *_port)
 	unsigned long flags;
 	u32 stat;
 	struct uart_port *port = (struct uart_port *)_port;
+	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
 
-	spin_lock_irqsave(&ltq_asc_lock, flags);
+	spin_lock_irqsave(&ltq_port->lock, flags);
 	/* clear any pending interrupts */
 	writel(ASC_IRNCR_EIR, port->membase + LTQ_ASC_IRNCR);
 	stat = readl(port->membase + LTQ_ASC_STATE);
@@ -266,7 +272,7 @@ static irqreturn_t lqasc_err_int(int irq, void *_port)
 		port->icount.overrun++;
 	}
 	asc_w32_mask(0, ASCWHBSTATE_CLRALL, port->membase + LTQ_ASC_WHBSTATE);
-	spin_unlock_irqrestore(&ltq_asc_lock, flags);
+	spin_unlock_irqrestore(&ltq_port->lock, flags);
 
 	return IRQ_HANDLED;
 }
@@ -275,10 +281,13 @@ static irqreturn_t lqasc_rx_int(int irq, void *_port)
 {
 	unsigned long flags;
 	struct uart_port *port = (struct uart_port *)_port;
-	spin_lock_irqsave(&ltq_asc_lock, flags);
+	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+
+	spin_lock_irqsave(&ltq_port->lock, flags);
 	writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
 	lqasc_rx_chars(port);
-	spin_unlock_irqrestore(&ltq_asc_lock, flags);
+	spin_unlock_irqrestore(&ltq_port->lock, flags);
+
 	return IRQ_HANDLED;
 }
 
@@ -309,11 +318,13 @@ lqasc_startup(struct uart_port *port)
 {
 	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
 	int retval;
+	unsigned long flags;
 
 	if (!IS_ERR(ltq_port->clk))
 		clk_enable(ltq_port->clk);
 	port->uartclk = clk_get_rate(ltq_port->fpiclk);
 
+	spin_lock_irqsave(&ltq_port->lock, flags);
 	asc_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
 		port->membase + LTQ_ASC_CLC);
 
@@ -330,6 +341,7 @@ lqasc_startup(struct uart_port *port)
 	wmb();
 	asc_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
 		     ASCCON_ROEN, port->membase + LTQ_ASC_CON);
+	spin_unlock_irqrestore(&ltq_port->lock, flags);
 
 	retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
 			     0, "asc_tx", port);
@@ -410,6 +422,7 @@ static void lqasc_set_termios(struct uart_port *port,
 	unsigned long flags;
 	u32 fdv = 0;
 	u32 reload = 0;
+	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
 
 	cflag = new->c_cflag;
 	iflag = new->c_iflag;
@@ -463,7 +476,7 @@ static void lqasc_set_termios(struct uart_port *port,
 	/* set error signals  - framing, parity  and overrun, enable receiver */
 	con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN;
 
-	spin_lock_irqsave(&ltq_asc_lock, flags);
+	spin_lock_irqsave(&ltq_port->lock, flags);
 
 	/* set up CON */
 	asc_w32_mask(0, con, port->membase + LTQ_ASC_CON);
@@ -490,7 +503,7 @@ static void lqasc_set_termios(struct uart_port *port,
 	/* enable rx */
 	writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
 
-	spin_unlock_irqrestore(&ltq_asc_lock, flags);
+	spin_unlock_irqrestore(&ltq_port->lock, flags);
 
 	/* Don't rewrite B0 */
 	if (tty_termios_baud_rate(new))
@@ -604,16 +617,14 @@ static void lqasc_console_putchar(struct uart_port *port, int ch)
 static void lqasc_serial_port_write(struct uart_port *port, const char *s,
 				    u_int count)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&ltq_asc_lock, flags);
 	uart_console_write(port, s, count, lqasc_console_putchar);
-	spin_unlock_irqrestore(&ltq_asc_lock, flags);
 }
 
 static void lqasc_console_write(struct console *co, const char *s, u_int count)
 {
+	unsigned long flags;
 	struct ltq_uart_port *ltq_port;
+	struct uart_port *port;
 
 	if (co->index >= MAXPORTS)
 		return;
@@ -622,7 +633,11 @@ static void lqasc_console_write(struct console *co, const char *s, u_int count)
 	if (!ltq_port)
 		return;
 
-	lqasc_serial_port_write(&ltq_port->port, s, count);
+	port = &ltq_port->port;
+
+	spin_lock_irqsave(&ltq_port->lock, flags);
+	lqasc_serial_port_write(port, s, count);
+	spin_unlock_irqrestore(&ltq_port->lock, flags);
 }
 
 static int __init lqasc_console_setup(struct console *co, char *options)
@@ -760,6 +775,8 @@ static int __init lqasc_probe(struct platform_device *pdev)
 	ltq_port->rx_irq = irqres[1].start;
 	ltq_port->err_irq = irqres[2].start;
 
+	spin_lock_init(&ltq_port->lock);
+
 	lqasc_port[line] = ltq_port;
 	platform_set_drvdata(pdev, ltq_port);
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH 6/7] tty: serial: lantiq: Remove unneeded header includes and macros
From: Songjun Wu @ 2018-06-12  5:40 UTC (permalink / raw)
  To: hua.ma, yixin.zhu, chuanhua.lei
  Cc: linux-mips, qi-ming.wu, linux-clk, linux-serial, devicetree,
	Songjun Wu, Greg Kroah-Hartman, linux-kernel, Jiri Slaby
In-Reply-To: <20180612054034.4969-1-songjun.wu@linux.intel.com>

Update the author list with Intel Corporation.
Sort the header includes in alphabetical orders.
Remove unneeded header includes and macros.

Signed-off-by: Songjun Wu <songjun.wu@linux.intel.com>
---

 drivers/tty/serial/lantiq.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 72aab1b05265..cc33208c93ac 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -6,24 +6,23 @@
  * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
  * Copyright (C) 2007 John Crispin <john@phrozen.org>
  * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
+ * Copyright (C) 2017 Intel Corporation.
  */
 
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/console.h>
-#include <linux/sysrq.h>
 #include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 
 #include <lantiq_soc.h>
 
@@ -43,7 +42,6 @@
 #define LTQ_ASC_STATE		0x0014
 #define LTQ_ASC_IRNCR		0x00F8
 #define LTQ_ASC_CLC		0x0000
-#define LTQ_ASC_ID		0x0008
 #define LTQ_ASC_PISEL		0x0004
 #define LTQ_ASC_TXFCON		0x0044
 #define LTQ_ASC_RXFCON		0x0040
@@ -51,16 +49,12 @@
 #define LTQ_ASC_BG		0x0050
 #define LTQ_ASC_FDV		0x0058
 #define LTQ_ASC_IRNEN		0x00F4
-
 #define ASC_IRNREN_TX		0x1
 #define ASC_IRNREN_RX		0x2
 #define ASC_IRNREN_ERR		0x4
-#define ASC_IRNREN_TX_BUF	0x8
 #define ASC_IRNCR_TIR		0x1
 #define ASC_IRNCR_RIR		0x2
 #define ASC_IRNCR_EIR		0x4
-
-#define ASCOPT_CSIZE		0x3
 #define TXFIFO_FL		1
 #define RXFIFO_FL		1
 #define ASCCLC_DISR		0x1
@@ -71,7 +65,6 @@
 #define ASCCON_M_7ASYNC		0x2
 #define ASCCON_ODD		0x00000020
 #define ASCCON_STP		0x00000080
-#define ASCCON_BRS		0x00000100
 #define ASCCON_FDE		0x00000200
 #define ASCCON_R		0x00008000
 #define ASCCON_FEN		0x00020000
@@ -80,7 +73,7 @@
 #define ASCSTATE_PE		0x00010000
 #define ASCSTATE_FE		0x00020000
 #define ASCSTATE_ROE		0x00080000
-#define ASCSTATE_ANY		(ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE)
+#define ASCSTATE_ANY		(ASCSTATE_ROE | ASCSTATE_PE | ASCSTATE_FE)
 #define ASCWHBSTATE_CLRREN	0x00000001
 #define ASCWHBSTATE_SETREN	0x00000002
 #define ASCWHBSTATE_CLRPE	0x00000004
-- 
2.11.0

^ permalink raw reply related

* [PATCH 7/7] tty: serial: lantiq: Add CCF support
From: Songjun Wu @ 2018-06-12  5:40 UTC (permalink / raw)
  To: hua.ma, yixin.zhu, chuanhua.lei
  Cc: linux-mips, qi-ming.wu, linux-clk, linux-serial, devicetree,
	Songjun Wu, Jiri Slaby, linux-kernel, Rob Herring,
	Greg Kroah-Hartman, Mark Rutland
In-Reply-To: <20180612054034.4969-1-songjun.wu@linux.intel.com>

Previous implementation uses platform-dependent API to get the clock.
Those functions are not available for other SoC which uses the same IP.
The CCF (Common Clock Framework) have an abstraction based APIs
for clock.
Change to use CCF APIs to get clock and rate.
So that different SoCs can use the same driver.
Clocks and clock-names are updated in device tree binding.

Signed-off-by: Songjun Wu <songjun.wu@linux.intel.com>

---

 .../devicetree/bindings/serial/lantiq_asc.txt      |  15 +++
 drivers/tty/serial/Kconfig                         |   2 +-
 drivers/tty/serial/lantiq.c                        | 101 +++++++++++++++++----
 3 files changed, 98 insertions(+), 20 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/lantiq_asc.txt b/Documentation/devicetree/bindings/serial/lantiq_asc.txt
index 3acbd309ab9d..608f0c87a4af 100644
--- a/Documentation/devicetree/bindings/serial/lantiq_asc.txt
+++ b/Documentation/devicetree/bindings/serial/lantiq_asc.txt
@@ -6,6 +6,10 @@ Required properties:
 - interrupts: the 3 (tx rx err) interrupt numbers. The interrupt specifier
   depends on the interrupt-parent interrupt controller.
 
+Optional properties:
+- clocks: Should contain frequency clock and gate clock
+- clock-names: Should be "freq" and "asc"
+
 Example:
 
 asc1: serial@e100c00 {
@@ -14,3 +18,14 @@ asc1: serial@e100c00 {
 	interrupt-parent = <&icu0>;
 	interrupts = <112 113 114>;
 };
+
+asc0: serial@600000 {
+	compatible = "lantiq,asc";
+	reg = <0x600000 0x100000>;
+	interrupt-parent = <&gic>;
+	interrupts = <GIC_SHARED 103 IRQ_TYPE_LEVEL_HIGH>,
+	<GIC_SHARED 105 IRQ_TYPE_LEVEL_HIGH>,
+	<GIC_SHARED 106 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&pll0aclk SSX4_CLK>, <&clkgate1 GATE_URT_CLK>;
+	clock-names = "freq", "asc";
+};
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 0f058df0b070..0f8ac5872a54 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1062,7 +1062,7 @@ config SERIAL_OMAP_CONSOLE
 
 config SERIAL_LANTIQ
 	bool "Lantiq serial driver"
-	depends on LANTIQ
+	depends on LANTIQ || INTEL_MIPS || COMPILE_TEST
 	select SERIAL_CORE
 	select SERIAL_CORE_CONSOLE
 	select SERIAL_EARLYCON
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index cc33208c93ac..fd7ba89daaa2 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -24,7 +24,9 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 
+#ifndef CONFIG_COMMON_CLK
 #include <lantiq_soc.h>
+#endif
 
 #define PORT_LTQ_ASC		111
 #define MAXPORTS		2
@@ -104,7 +106,7 @@ static struct uart_driver lqasc_reg;
 struct ltq_uart_port {
 	struct uart_port	port;
 	/* clock used to derive divider */
-	struct clk		*fpiclk;
+	struct clk		*freqclk;
 	/* clock gating of the ASC core */
 	struct clk		*clk;
 	unsigned int		tx_irq;
@@ -120,7 +122,6 @@ static inline struct ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
 
 static void lqasc_stop_tx(struct uart_port *port)
 {
-	return;
 }
 
 static void lqasc_start_tx(struct uart_port *port)
@@ -291,8 +292,7 @@ static unsigned int lqasc_tx_empty(struct uart_port *port)
 	return status ? 0 : TIOCSER_TEMT;
 }
 
-static unsigned int
-lqasc_get_mctrl(struct uart_port *port)
+static unsigned int lqasc_get_mctrl(struct uart_port *port)
 {
 	return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR;
 }
@@ -301,21 +301,65 @@ static void lqasc_set_mctrl(struct uart_port *port, u_int mctrl)
 {
 }
 
-static void
-lqasc_break_ctl(struct uart_port *port, int break_state)
+static void lqasc_break_ctl(struct uart_port *port, int break_state)
 {
 }
 
-static int
-lqasc_startup(struct uart_port *port)
+static void lqasc_fdv_and_reload_get(struct ltq_uart_port *ltq_port,
+				     unsigned int baudrate, unsigned int *fdv,
+				     unsigned int *reload)
+{
+	unsigned int asc_clk = clk_get_rate(ltq_port->freqclk);
+	unsigned int baudrate1 = baudrate * 8192;
+	unsigned long long baudrate2 = (unsigned long long)baudrate * 1000;
+	unsigned long long fdv_over_bg_fpi;
+	unsigned long long fdv_over_bg;
+	unsigned long long difference;
+	unsigned long long min_difference;
+	unsigned int bg;
+
+	/* Sanity check first */
+	if (baudrate >= (asc_clk >> 4)) {
+		pr_err("%s current fpi clock %u can't provide baudrate %u!!!\n",
+		       __func__, asc_clk, baudrate);
+		return;
+	}
+
+	min_difference = UINT_MAX;
+	fdv_over_bg_fpi = baudrate1;
+
+	for (bg = 1; bg <= 8192; bg++, fdv_over_bg_fpi += baudrate1) {
+		fdv_over_bg = fdv_over_bg_fpi + asc_clk / 2;
+		do_div(fdv_over_bg, asc_clk);
+		if (fdv_over_bg <= 512) {
+			difference = fdv_over_bg * asc_clk * 1000;
+			do_div(difference, 8192 * bg);
+			if (difference < baudrate2)
+				difference = baudrate2 - difference;
+			else
+				difference -= baudrate2;
+			if (difference < min_difference) {
+				*fdv = (unsigned int)fdv_over_bg & 511;
+				*reload = bg - 1;
+				min_difference = difference;
+			}
+			/* Perfect one found */
+			if (min_difference == 0)
+				break;
+		}
+	}
+}
+
+static int lqasc_startup(struct uart_port *port)
 {
 	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
 	int retval;
 	unsigned long flags;
 
 	if (!IS_ERR(ltq_port->clk))
-		clk_enable(ltq_port->clk);
-	port->uartclk = clk_get_rate(ltq_port->fpiclk);
+		clk_prepare_enable(ltq_port->clk);
+
+	port->uartclk = clk_get_rate(ltq_port->freqclk);
 
 	spin_lock_irqsave(&ltq_port->lock, flags);
 	asc_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
@@ -378,6 +422,7 @@ static void lqasc_shutdown(struct uart_port *port)
 	int i = 100;
 
 	writel(0, port->membase + LTQ_ASC_CON);
+	writel(0, port->membase + LTQ_ASC_IRNEN);
 	free_irq(ltq_port->tx_irq, port);
 	free_irq(ltq_port->rx_irq, port);
 	free_irq(ltq_port->err_irq, port);
@@ -401,7 +446,7 @@ static void lqasc_shutdown(struct uart_port *port)
 	spin_unlock_irqrestore(&ltq_port->lock, flags);
 
 	if (!IS_ERR(ltq_port->clk))
-		clk_disable(ltq_port->clk);
+		clk_disable_unprepare(ltq_port->clk);
 }
 
 static void lqasc_set_termios(struct uart_port *port,
@@ -476,9 +521,13 @@ static void lqasc_set_termios(struct uart_port *port,
 
 	/* Set baud rate - take a divider of 2 into account */
 	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+	if (baud)
+		lqasc_fdv_and_reload_get(ltq_port, baud, &fdv, &reload);
+
 	divisor = uart_get_divisor(port, baud);
 	divisor = divisor / 2 - 1;
 
+	/* Disable the baudrate generator */
 	asc_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
 	/* Ensure the setting is effect before enabling */
 	wmb();
@@ -490,6 +539,9 @@ static void lqasc_set_termios(struct uart_port *port,
 	/* now we can write the new baudrate into the register */
 	writel(fdv, port->membase + LTQ_ASC_FDV);
 
+	/* Ensure baud configuration takes effetive before enabling */
+	wmb();
+
 	/* turn the baudrate generator back on */
 	asc_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
 
@@ -546,7 +598,7 @@ static int lqasc_request_port(struct uart_port *port)
 	if (port->flags & UPF_IOREMAP) {
 		port->membase = devm_ioremap_nocache(&pdev->dev,
 						     port->mapbase, size);
-		if (port->membase == NULL)
+		if (!port->membase)
 			return -ENOMEM;
 	}
 	return 0;
@@ -652,9 +704,9 @@ static int __init lqasc_console_setup(struct console *co, char *options)
 	port = &ltq_port->port;
 
 	if (!IS_ERR(ltq_port->clk))
-		clk_enable(ltq_port->clk);
+		clk_prepare_enable(ltq_port->clk);
 
-	port->uartclk = clk_get_rate(ltq_port->fpiclk);
+	port->uartclk = clk_get_rate(ltq_port->freqclk);
 
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -729,8 +781,11 @@ static int __init lqasc_probe(struct platform_device *pdev)
 	}
 
 	/* check if this is the console port */
-	if (mmres->start != CPHYSADDR(LTQ_EARLY_ASC))
-		line = 1;
+	line = of_alias_get_id(node, "serial");
+	if (line < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", line);
+		return line;
+	}
 
 	if (lqasc_port[line]) {
 		dev_err(&pdev->dev, "port %d already allocated\n", line);
@@ -755,14 +810,22 @@ static int __init lqasc_probe(struct platform_device *pdev)
 	port->irq	= irqres[0].start;
 	port->mapbase	= mmres->start;
 
-	ltq_port->fpiclk = clk_get_fpi();
-	if (IS_ERR(ltq_port->fpiclk)) {
+#ifdef CONFIG_COMMON_CLK
+	ltq_port->freqclk = devm_clk_get(&pdev->dev, "freq");
+#else
+	ltq_port->freqclk = clk_get_fpi();
+#endif
+	if (IS_ERR(ltq_port->freqclk)) {
 		pr_err("failed to get fpi clk\n");
 		return -ENOENT;
 	}
 
 	/* not all asc ports have clock gates, lets ignore the return code */
+#ifdef CONFIG_COMMON_CLK
+	ltq_port->clk = devm_clk_get(&pdev->dev, "asc");
+#else
 	ltq_port->clk = clk_get(&pdev->dev, NULL);
+#endif
 
 	ltq_port->tx_irq = irqres[0].start;
 	ltq_port->rx_irq = irqres[1].start;
@@ -790,7 +853,7 @@ static struct platform_driver lqasc_driver = {
 	},
 };
 
-int __init init_lqasc(void)
+static int __init init_lqasc(void)
 {
 	int ret;
 
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH 7/7] tty: serial: lantiq: Add CCF support
From: kbuild test robot @ 2018-06-12  8:07 UTC (permalink / raw)
  Cc: kbuild-all, hua.ma, yixin.zhu, chuanhua.lei, linux-mips,
	qi-ming.wu, linux-clk, linux-serial, devicetree, Songjun Wu,
	Jiri Slaby, linux-kernel, Rob Herring, Greg Kroah-Hartman,
	Mark Rutland
In-Reply-To: <20180612054034.4969-8-songjun.wu@linux.intel.com>

[-- Attachment #1: Type: text/plain, Size: 1640 bytes --]

Hi Songjun,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.17 next-20180612]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Songjun-Wu/MIPS-intel-add-initial-support-for-Intel-MIPS-SoCs/20180612-134457
config: s390-allmodconfig (attached as .config)
compiler: s390x-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=s390 

All errors (new ones prefixed by >>):

>> drivers/tty/serial/lantiq.c:28:10: fatal error: lantiq_soc.h: No such file or directory
    #include <lantiq_soc.h>
             ^~~~~~~~~~~~~~
   compilation terminated.

vim +28 drivers/tty/serial/lantiq.c

2f0fc415 John Crispin 2011-04-05  26  
c17405a9 Songjun Wu   2018-06-12  27  #ifndef CONFIG_COMMON_CLK
2f0fc415 John Crispin 2011-04-05 @28  #include <lantiq_soc.h>
c17405a9 Songjun Wu   2018-06-12  29  #endif
2f0fc415 John Crispin 2011-04-05  30  

:::::: The code at line 28 was first introduced by commit
:::::: 2f0fc4159a6abc20b13569522c545150b99485cf SERIAL: Lantiq: Add driver for MIPS Lantiq SOCs.

:::::: TO: John Crispin <blogic@openwrt.org>
:::::: CC: Ralf Baechle <ralf@linux-mips.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 50334 bytes --]

^ permalink raw reply

* Re: [PATCH 4/7] tty: serial: lantiq: Always use readl()/writel()
From: Andy Shevchenko @ 2018-06-12  8:13 UTC (permalink / raw)
  To: Songjun Wu
  Cc: hua.ma, yixin.zhu, chuanhua.lei, Linux MIPS Mailing List,
	qi-ming.wu, linux-clk, open list:SERIAL DRIVERS, devicetree,
	James Hogan, Jiri Slaby, Linux Kernel Mailing List,
	Greg Kroah-Hartman, Ralf Baechle
In-Reply-To: <20180612054034.4969-5-songjun.wu@linux.intel.com>

On Tue, Jun 12, 2018 at 8:40 AM, Songjun Wu <songjun.wu@linux.intel.com> wrote:
> Previous implementation uses platform-dependent functions
> ltq_w32()/ltq_r32() to access registers. Those functions are not
> available for other SoC which uses the same IP.
> Change to OS provided readl()/writel() and readb()/writeb(), so
> that different SoCs can use the same driver.

This patch consists 2 or even 3 ones:
- whitespace shuffling (indentation fixes, blank lines), I dunno if
it's needed at all
- some new registers / bits
- actual switch to readl() / writel()

Please, split.

> +#define asc_w32_mask(clear, set, reg)  \
> +       ({ typeof(reg) reg_ = (reg);    \
> +       writel((readl(reg_) & ~(clear)) | (set), reg_); })

This would be better as a static inline helper, and name is completely
misleading, it doesn't mask the register bits, it _updates_ them.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH] tty: serial: add error handling for try_module_get
From: Andy Shevchenko @ 2018-06-12  8:23 UTC (permalink / raw)
  To: Zhouyang Jia
  Cc: Jason Wessel, Daniel Thompson, Greg Kroah-Hartman, Jiri Slaby,
	kgdb-bugreport, open list:SERIAL DRIVERS,
	Linux Kernel Mailing List
In-Reply-To: <1528779046-42341-1-git-send-email-jiazhouyang09@gmail.com>

On Tue, Jun 12, 2018 at 7:50 AM, Zhouyang Jia <jiazhouyang09@gmail.com> wrote:
> When try_module_get fails, the lack of error-handling code may
> cause unexpected results.

What results? What is recovery approach here?
How printing message change a behaviour?

> This patch adds error-handling code after calling try_module_get.

> +       if (!kgdb_connected) {
> +               if (!try_module_get(THIS_MODULE))
> +                       printk(KERN_ERR "kgdboc: cannot get module.\n");

So, what's wrong with pr_err() ?

> +       }

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH] serial: 8250_dw: 8250_dw need to depend on COMMON_CLK
From: Geert Uytterhoeven @ 2018-06-12  8:31 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Corentin Labbe, Greg KH, Jiri Slaby, Linux Kernel Mailing List,
	open list:SERIAL DRIVERS
In-Reply-To: <CAHp75Ve3nDsoEh0dL=xF3oei_GM9tPn_72=je+FESO=hJFm4uA@mail.gmail.com>

On Mon, Jun 11, 2018 at 11:03 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Wed, Jun 6, 2018 at 10:27 PM Corentin Labbe <clabbe@baylibre.com> wrote:
> > This patch fix the following build error on M68K:

Not plain m68k, but coldfire only (and MIPS AR7, I guess).

> > drivers/tty/serial/8250/8250_dw.o: In function `dw8250_set_termios':
> > 8250_dw.c:(.text+0x50c): undefined reference to `clk_round_rate'
> > 8250_dw.c:(.text+0x594): undefined reference to `clk_set_rate'
> >
> > So 8250_dw need to depend on COMMON_CLK.
> >
>
> Makes sense.
> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

Please see "[PATCH 0/3] Legacy clock drivers: Normalize clk API"
(https://lkml.org/lkml/2018/6/11/122).

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH] serial: 8250_dw: 8250_dw need to depend on COMMON_CLK
From: Andy Shevchenko @ 2018-06-12  8:36 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Corentin Labbe, Greg KH, Jiri Slaby, Linux Kernel Mailing List,
	open list:SERIAL DRIVERS
In-Reply-To: <CAMuHMdVZjPRknHY-3b7qr+FgwWmK3g3rCgjjK09Thh2EOLXbcQ@mail.gmail.com>

On Tue, Jun 12, 2018 at 11:31 AM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> On Mon, Jun 11, 2018 at 11:03 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
>> On Wed, Jun 6, 2018 at 10:27 PM Corentin Labbe <clabbe@baylibre.com> wrote:
>> > This patch fix the following build error on M68K:
>
> Not plain m68k, but coldfire only (and MIPS AR7, I guess).
>
>> > drivers/tty/serial/8250/8250_dw.o: In function `dw8250_set_termios':
>> > 8250_dw.c:(.text+0x50c): undefined reference to `clk_round_rate'
>> > 8250_dw.c:(.text+0x594): undefined reference to `clk_set_rate'
>> >
>> > So 8250_dw need to depend on COMMON_CLK.
>> >
>>
>> Makes sense.
>> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
>
> Please see "[PATCH 0/3] Legacy clock drivers: Normalize clk API"
> (https://lkml.org/lkml/2018/6/11/122).

Indeed, your solution is better.
So, I need to withdraw my tag.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH 3/7] MIPS: intel: Add initial support for Intel MIPS SoCs
From: James Hogan @ 2018-06-12 11:23 UTC (permalink / raw)
  To: Songjun Wu
  Cc: hua.ma, yixin.zhu, chuanhua.lei, linux-mips, qi-ming.wu,
	linux-clk, linux-serial, devicetree, linux-kernel, Rob Herring,
	Ralf Baechle, Mark Rutland
In-Reply-To: <20180612054034.4969-4-songjun.wu@linux.intel.com>

[-- Attachment #1: Type: text/plain, Size: 8818 bytes --]

Hi,

Good to see this patch!

On Tue, Jun 12, 2018 at 01:40:30PM +0800, Songjun Wu wrote:
> diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
> index ac7ad54f984f..bcd647060f3e 100644
> --- a/arch/mips/Kbuild.platforms
> +++ b/arch/mips/Kbuild.platforms
> @@ -12,6 +12,7 @@ platforms += cobalt
>  platforms += dec
>  platforms += emma
>  platforms += generic
> +platforms += intel-mips

What are the main things preventing this from moving to the generic
platform? Is it mainly the use of EVA (which generic doesn't yet
support)?

> diff --git a/arch/mips/include/asm/mach-intel-mips/kernel-entry-init.h b/arch/mips/include/asm/mach-intel-mips/kernel-entry-init.h
> new file mode 100644
> index 000000000000..3893855b60c6
> --- /dev/null
> +++ b/arch/mips/include/asm/mach-intel-mips/kernel-entry-init.h
...
> +	/*
> +	 * Get Config.K0 value and use it to program
> +	 * the segmentation registers

Please can you describe (maybe with a table) the segment layout in human
readable terms so the reader doesn't need to decode the SegCtl registers
to understand where everything is in the virtual address space?

> diff --git a/arch/mips/boot/dts/intel-mips/Makefile b/arch/mips/boot/dts/intel-mips/Makefile
> new file mode 100644
> index 000000000000..b16c0081639c
> --- /dev/null
> +++ b/arch/mips/boot/dts/intel-mips/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +dtb-$(CONFIG_DTB_INTEL_MIPS_GRX500)	+= easy350_anywan.dtb
> +obj-y	+= $(patsubst %.dtb, %.dtb.o, $(dtb-y))

This needs updating to obj-$(CONFIG_BUILTIN_DTB) as per commit
fca3aa166422 ("MIPS: dts: Avoid unneeded built-in.a in DTS dirs") in
linux-next.

> diff --git a/arch/mips/intel-mips/Makefile b/arch/mips/intel-mips/Makefile
> new file mode 100644
> index 000000000000..9f272d06eecd
> --- /dev/null
> +++ b/arch/mips/intel-mips/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_INTEL_MIPS)	+= prom.o irq.o time.o

You can use obj-y, since this Makefile is only included if
CONFIG_INTEL_MIPS=y (i.e. via the platform-$(CONFIG_INTEL_MIPS) below).

Also please split each file onto separate "obj-y += whatever.o" lines.

> diff --git a/arch/mips/intel-mips/Platform b/arch/mips/intel-mips/Platform
> new file mode 100644
> index 000000000000..b34750eeaeb0
> --- /dev/null
> +++ b/arch/mips/intel-mips/Platform
> @@ -0,0 +1,11 @@
> +#
> +# MIPs SoC platform
> +#
> +
> +platform-$(CONFIG_INTEL_MIPS)			+= intel-mips/

^^^ (this is what ensures the Makefile is only included for this
platform)

> diff --git a/arch/mips/intel-mips/irq.c b/arch/mips/intel-mips/irq.c
> new file mode 100644
> index 000000000000..00637a5cdd20
> --- /dev/null
> +++ b/arch/mips/intel-mips/irq.c
> @@ -0,0 +1,36 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2016 Intel Corporation.
> + */
> +#include <linux/init.h>
> +#include <linux/irqchip.h>
> +#include <linux/of_irq.h>
> +#include <asm/irq.h>
> +
> +#include <asm/irq_cpu.h>
> +
> +void __init arch_init_irq(void)
> +{
> +	struct device_node *intc_node;
> +
> +	pr_info("EIC is %s\n", cpu_has_veic ? "on" : "off");
> +	pr_info("VINT is %s\n", cpu_has_vint ? "on" : "off");
> +
> +	intc_node = of_find_compatible_node(NULL, NULL,
> +					    "mti,cpu-interrupt-controller");
> +	if (!cpu_has_veic && !intc_node)
> +		mips_cpu_irq_init();
> +
> +	irqchip_init();
> +}
> +
> +int get_c0_perfcount_int(void)
> +{
> +	return gic_get_c0_perfcount_int();
> +}
> +EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
> +
> +unsigned int get_c0_compare_int(void)
> +{
> +	return gic_get_c0_compare_int();
> +}

Worth having get_c0_fdc_int() too for the "Fast Debug Channel"?

> diff --git a/arch/mips/intel-mips/prom.c b/arch/mips/intel-mips/prom.c
> new file mode 100644
> index 000000000000..9407858ddc94
> --- /dev/null
> +++ b/arch/mips/intel-mips/prom.c
> @@ -0,0 +1,184 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2014 Lei Chuanhua <Chuanhua.lei@lantiq.com>
> + * Copyright (C) 2016 Intel Corporation.
> + */
> +#include <linux/init.h>
> +#include <linux/export.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_fdt.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include <asm/mips-cps.h>
> +#include <asm/smp-ops.h>
> +#include <asm/dma-coherence.h>
> +#include <asm/prom.h>
> +
> +#define IOPORT_RESOURCE_START   0x10000000
> +#define IOPORT_RESOURCE_END     0xffffffff
> +#define IOMEM_RESOURCE_START    0x10000000
> +#define IOMEM_RESOURCE_END      0xffffffff

The _END ones seem to be unused?

> +static void __init prom_init_cmdline(void)
> +{
> +	int i;
> +	int argc;
> +	char **argv;
> +
> +	/*
> +	 * If u-boot pass parameters, it is ok, however, if without u-boot
> +	 * JTAG or other tool has to reset all register value before it goes
> +	 * emulation most likely belongs to this category
> +	 */
> +	if (fw_arg0 == 0 || fw_arg1 == 0)
> +		return;
> +
> +	argc = fw_arg0;
> +	argv = (char **)KSEG1ADDR(fw_arg1);
> +
> +	arcs_cmdline[0] = '\0';
> +
> +	for (i = 0; i < argc; i++) {
> +		char *p = (char *)KSEG1ADDR(argv[i]);
> +
> +		if (argv[i] && *p) {
> +			strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
> +			strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
> +		}
> +	}

Please describe the boot register protocol in the commit message and/or
a comment in this function.

Is it compatible with the UHI boot protocol, such that this could
potentially be converted to use the generic platform in future?

> +}
> +
> +static int __init plat_enable_iocoherency(void)
> +{
> +	int supported = 0;
> +
> +	if (mips_cps_numiocu(0) != 0) {
> +		/* Nothing special needs to be done to enable coherency */
> +		pr_info("Coherence Manager IOCU detected\n");
> +		/* Second IOCU for MPE or other master access register */
> +		write_gcr_reg0_base(0xa0000000);
> +		write_gcr_reg0_mask(0xf8000000 | CM_GCR_REGn_MASK_CMTGT_IOCU1);
> +		supported = 1;
> +	}
> +
> +	/* hw_coherentio = supported; */
> +
> +	return supported;
> +}
> +
> +static void __init plat_setup_iocoherency(void)
> +{
> +#ifdef CONFIG_DMA_NONCOHERENT
> +	/*
> +	 * Kernel has been configured with software coherency
> +	 * but we might choose to turn it off and use hardware
> +	 * coherency instead.

That sounds a big risky. Software coherency will I think perform cache
line invalidation when syncing buffers from device to CPU (see
__dma_sync_virtual), so that the underlying RAM written by the
supposedly incoherent DMA is visible. If its coherent afterall then it
may be sat in a dirty line in the cache, and not have been written back
to RAM yet before it gets invalidated?

> +	 */
> +	if (plat_enable_iocoherency()) {
> +		if (coherentio == IO_COHERENCE_DISABLED)
> +			pr_info("Hardware DMA cache coherency disabled\n");
> +		else
> +			pr_info("Hardware DMA cache coherency enabled\n");
> +	} else {
> +		if (coherentio == IO_COHERENCE_ENABLED)
> +			pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n");
> +		else
> +			pr_info("Software DMA cache coherency enabled\n");
> +	}
> +#else
> +	if (!plat_enable_iocoherency())
> +		panic("Hardware DMA cache coherency not supported!");
> +#endif
> +}


> +void __init device_tree_init(void)
> +{
> +	if (!initial_boot_params)
> +		return;

Redundant check. unflatten_and_copy_device_tree() now handles that and
emits a message.

> +
> +	unflatten_and_copy_device_tree();
> +}
> +
> +#define CPC_BASE_ADDR		0x12310000

Please put this at the top of the file with other #defines.

> +
> +phys_addr_t mips_cpc_default_phys_base(void)
> +{
> +	return CPC_BASE_ADDR;
> +}

> diff --git a/arch/mips/intel-mips/time.c b/arch/mips/intel-mips/time.c
> new file mode 100644
> index 000000000000..77ad4014fe9d
> --- /dev/null
> +++ b/arch/mips/intel-mips/time.c
> @@ -0,0 +1,56 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2016 Intel Corporation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clocksource.h>
> +#include <linux/of.h>
> +
> +#include <asm/time.h>
> +
> +static inline u32 get_counter_resolution(void)
> +{
> +	u32 res;
> +
> +	__asm__ __volatile__(".set	push\n"

Preferably each line of asm should end \n\t and the final line doesn't
need \n or \t. Look at the .s compiler output to see the difference.

> +			     ".set	mips32r2\n"
> +			     "rdhwr	%0, $3\n"

Hmm, it'd be nice to abstract this in mipsregs.h, but that can always
wait. You could use MIPS_HWR_CCRES though (i.e. off top of my head
something like "%0, $%1\n" and have a "i" (MIPS_HWR_CCRES) input.

> +			     ".set pop\n"
> +			     : "=&r" (res)

I don't think you strictly need an early clobber there since there are
no register inputs, "=r" should do fine.

> +			     : /* no input */
> +			     : "memory");

I don't think that operation clobbers any memory?

Thanks
James

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox