2018-06-12 05:44:05

by Songjun Wu

[permalink] [raw]
Subject: [PATCH 0/7] MIPS: intel: add initial support for Intel MIPS SoCs

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



2018-06-12 05:42:29

by Songjun Wu

[permalink] [raw]
Subject: [PATCH 6/7] tty: serial: lantiq: Remove unneeded header includes and macros

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 <[email protected]>
---

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 <[email protected]>
* Copyright (C) 2007 John Crispin <[email protected]>
* Copyright (C) 2010 Thomas Langer, <[email protected]>
+ * 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


2018-06-12 05:42:48

by Songjun Wu

[permalink] [raw]
Subject: [PATCH 7/7] tty: serial: lantiq: Add CCF support

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 <[email protected]>

---

.../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


2018-06-12 05:42:52

by Songjun Wu

[permalink] [raw]
Subject: [PATCH 1/7] MIPS: dts: Add aliases node for lantiq danube serial

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 <[email protected]>
---

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


2018-06-12 05:43:02

by Songjun Wu

[permalink] [raw]
Subject: [PATCH 2/7] clk: intel: Add clock driver for GRX500 SoC

From: Yixin Zhu <[email protected]>

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 <[email protected]>

Signed-off-by: Songjun Wu <[email protected]>
---

.../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 <[email protected]>
+ *
+ */
+
+#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 <[email protected]>
+ *
+ */
+
+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 <[email protected]>
+ *
+ */
+
+#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 <[email protected]>
+ *
+ */
+
+#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


2018-06-12 05:43:15

by Songjun Wu

[permalink] [raw]
Subject: [PATCH 5/7] tty: serial: lantiq: Convert global lock to per device lock

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 <[email protected]>
---

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


2018-06-12 05:43:26

by Songjun Wu

[permalink] [raw]
Subject: [PATCH 3/7] MIPS: intel: Add initial support for Intel MIPS SoCs

From: Hua Ma <[email protected]>

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 <[email protected]>
Signed-off-by: Songjun Wu <[email protected]>
---

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 <[email protected]>
+ * 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 <[email protected]>
+ * 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 ([email protected])
+ * Leonid Yegoshin ([email protected])
+ * 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 ([email protected])
+ * Copyright (C) 2012 MIPS Technologies, Inc.
+ * Copyright (C) 2014 Lei Chuanhua <[email protected]>
+ * 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 <[email protected]>
+ * 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


2018-06-12 05:43:39

by Songjun Wu

[permalink] [raw]
Subject: [PATCH 4/7] tty: serial: lantiq: Always use readl()/writel()

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 <[email protected]>
---

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


2018-06-12 08:10:34

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 7/7] tty: serial: lantiq: Add CCF support

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 <[email protected]>
:::::: CC: Ralf Baechle <[email protected]>

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


Attachments:
(No filename) (1.64 kB)
.config.gz (49.15 kB)
Download all attachments

2018-06-12 08:16:07

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH 4/7] tty: serial: lantiq: Always use readl()/writel()

On Tue, Jun 12, 2018 at 8:40 AM, Songjun Wu <[email protected]> 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

2018-06-12 11:26:32

by James Hogan

[permalink] [raw]
Subject: Re: [PATCH 3/7] MIPS: intel: Add initial support for Intel MIPS SoCs

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 <[email protected]>
> + * 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


Attachments:
(No filename) (8.91 kB)
signature.asc (235.00 B)
Download all attachments

2018-06-12 22:25:23

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 1/7] MIPS: dts: Add aliases node for lantiq danube serial

On Tue, Jun 12, 2018 at 01:40:28PM +0800, Songjun Wu wrote:
> 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 <[email protected]>
> ---
>
> 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 {

Fix this to be lower case hex while you are at it.

> compatible = "lantiq,asc";
> reg = <0xE100C00 0x400>;
> interrupt-parent = <&icu0>;
> --
> 2.11.0
>

2018-06-12 22:32:54

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 3/7] MIPS: intel: Add initial support for Intel MIPS SoCs

On Tue, Jun 12, 2018 at 01:40:30PM +0800, Songjun Wu wrote:
> From: Hua Ma <[email protected]>
>
> 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 <[email protected]>
> Signed-off-by: Songjun Wu <[email protected]>
> ---
>
> 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 +++++++++++++++++++++

Please split dts files to separate patch.


> 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";

A board should have a board specific compatible, too.

> + chosen {
> + bootargs = "earlycon=lantiq,0x16600000 clk_ignore_unused";
> + stdout-path = "serial0";
> + };
> +
> + memory@0 {

memory@20000000

> + 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";

This needs to be documented.

> +
> + 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";
> + };
> +};

2018-06-12 22:39:15

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 2/7] clk: intel: Add clock driver for GRX500 SoC

On Tue, Jun 12, 2018 at 01:40:29PM +0800, Songjun Wu wrote:
> From: Yixin Zhu <[email protected]>
>
> 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 <[email protected]>
>
> Signed-off-by: Songjun Wu <[email protected]>

Need a blank line before the SoB's and not one in the middle.

> ---
>
> .../devicetree/bindings/clock/intel,grx500-clk.txt | 46 ++

Please split bindings to separate patch.

> 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

These would need to be enumerated with all possible values. However, see
below.

> +- 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";
> + };

We generally don't do a clock node per clock or few clocks but rather 1
clock node per clock controller block. See any recent clock bindings.

Rob

2018-06-12 22:40:37

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 7/7] tty: serial: lantiq: Add CCF support

On Tue, Jun 12, 2018 at 01:40:34PM +0800, Songjun Wu wrote:
> 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 <[email protected]>
>
> ---
>
> .../devicetree/bindings/serial/lantiq_asc.txt | 15 +++

Please split bindings to separate patch.

> 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>;

1MB of address space? That wastes a lot of virtual space on 32-bit
systems. Just make the size the actual used range.

> + 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";
> +};

2018-06-14 06:39:59

by Songjun Wu

[permalink] [raw]
Subject: Re: [PATCH 7/7] tty: serial: lantiq: Add CCF support



On 6/13/2018 6:39 AM, Rob Herring wrote:
> On Tue, Jun 12, 2018 at 01:40:34PM +0800, Songjun Wu wrote:
>> 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 <[email protected]>
>>
>> ---
>>
>> .../devicetree/bindings/serial/lantiq_asc.txt | 15 +++
> Please split bindings to separate patch.
Thanks.
It will be split to two separate patches, one for bindings, the other
for code.
>> 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>;
> 1MB of address space? That wastes a lot of virtual space on 32-bit
> systems. Just make the size the actual used range.
The size of address space will be updated to the actual used range.
>> + 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";
>> +};


2018-06-14 07:06:11

by Songjun Wu

[permalink] [raw]
Subject: Re: [PATCH 4/7] tty: serial: lantiq: Always use readl()/writel()



On 6/12/2018 4:13 PM, Andy Shevchenko wrote:
> On Tue, Jun 12, 2018 at 8:40 AM, Songjun Wu <[email protected]> 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.
It will be split to four patches, coding style, new registers,
readl()/writel() and asc_update_bits.
>> +#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.
It will be changed to asc_update_bits.


2018-06-14 08:02:27

by Hua Ma

[permalink] [raw]
Subject: Re: [PATCH 3/7] MIPS: intel: Add initial support for Intel MIPS SoCs


On 6/13/2018 6:31 AM, Rob Herring wrote:
> On Tue, Jun 12, 2018 at 01:40:30PM +0800, Songjun Wu wrote:
>> From: Hua Ma <[email protected]>
>>
>> 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 <[email protected]>
>> Signed-off-by: Songjun Wu <[email protected]>
>> ---
>>
>> 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 +++++++++++++++++++++
> Please split dts files to separate patch.
Thanks,
it will be split into separate patches: one for dts, one for mips codes
and one for the document.
>> 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";
> A board should have a board specific compatible, too.
The board compatible will be added.
>
>> + chosen {
>> + bootargs = "earlycon=lantiq,0x16600000 clk_ignore_unused";
>> + stdout-path = "serial0";
>> + };
>> +
>> + memory@0 {
> memory@20000000
The memory address will be changed to @20000000.
>
>> + 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";
> This needs to be documented.
The compatible will be updated in the document.


2018-06-14 08:41:13

by Zhu, Yi Xin

[permalink] [raw]
Subject: Re: [PATCH 2/7] clk: intel: Add clock driver for GRX500 SoC



On 6/13/2018 6:37 AM, Rob Herring wrote:
> On Tue, Jun 12, 2018 at 01:40:29PM +0800, Songjun Wu wrote:
>> From: Yixin Zhu <[email protected]>
>>
>> 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 <[email protected]>
>>
>> Signed-off-by: Songjun Wu <[email protected]>
>
> Need a blank line before the SoB's and not one in the middle.
Thanks.
Blank line in the middle of sign-off will be removed.
A new blank line will be added before SoB's.

>
>> ---
>>
>> .../devicetree/bindings/clock/intel,grx500-clk.txt | 46 ++
>
> Please split bindings to separate patch.
>
>> 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
>
> These would need to be enumerated with all possible values. However, see
> below.
All possible values will be listed.

>
>> +- 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";
>> + };
>
> We generally don't do a clock node per clock or few clocks but rather 1
> clock node per clock controller block. See any recent clock bindings.
>
> Rob
Do you mean only one example is needed per clock controller block?
cpuclk is not needed in the document?

2018-06-14 09:26:55

by Zhu, Yi Xin

[permalink] [raw]
Subject: Re: [PATCH 3/7] MIPS: intel: Add initial support for Intel MIPS SoCs



On 6/12/2018 7:23 PM, James Hogan wrote:
> 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)?
>
Yes. It's mainly because of EVA.

>> 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?
>
Will add detailed EVA mapping description in code comments.

>> 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.
>
Will use obj-y.
Will split it into per line per .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/
>
> ^^^ (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"?
>
FDC not used in our product.

>> 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 <[email protected]>
>> + * 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?
>
Will remove unused _END macros.

>> +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.
>Will add boot register protocol description in code comment.

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

>> +}
>> +
>> +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?
>
The comment in code is not accurate.
HW coherence is not supported and software coherence is always enabled.
Will correct the comments and clean the code.

>> + */
>> + 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.
>
Will remove the redundant check.

>> +
>> + unflatten_and_copy_device_tree();
>> +}
>> +
>> +#define CPC_BASE_ADDR 0x12310000
>
> Please put this at the top of the file with other #defines.
>
Will move this to the top 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?
>
Will replace the assembly code with fixed value 2 as the chip resolution
is the half of the clock.

> Thanks
> James
>
Thanks
Yixin

2018-06-14 10:06:08

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 1/7] MIPS: dts: Add aliases node for lantiq danube serial

On Tue, Jun 12, 2018 at 7:40 AM, Songjun Wu <[email protected]> wrote:
> 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 <[email protected]>
> ---
>
> 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;
> + };
> +

You generally want the aliases to be part of the board specific file,
not every board numbers their serial ports in the same way.

Arnd

2018-06-14 10:08:02

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 4/7] tty: serial: lantiq: Always use readl()/writel()

On Tue, Jun 12, 2018 at 7:40 AM, Songjun Wu <[email protected]> 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.
>
> Signed-off-by: Songjun Wu <[email protected]>

Are there any big-endian machines using this driver? The original definition
of ltq_r32() uses non-byteswapping __raw_readl() etc, which suggests
that the registers might be wired up in a way that matches the CPU
endianess (this is usally a bad idea in hardware design, but nothing
we can influence in the OS).

When you change it to readl(), that will breaks all machines that rely
on the old behavior on big-endian kernels.

Arnd

2018-06-14 14:10:46

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 2/7] clk: intel: Add clock driver for GRX500 SoC

On Thu, Jun 14, 2018 at 2:40 AM, yixin zhu <[email protected]> wrote:
>
>
> On 6/13/2018 6:37 AM, Rob Herring wrote:
>>
>> On Tue, Jun 12, 2018 at 01:40:29PM +0800, Songjun Wu wrote:
>>>
>>> From: Yixin Zhu <[email protected]>
>>>
>>> PLL of GRX500 provide clock to DDR, CPU, and peripherals as show below

[...]

>>> +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";
>>> + };
>>
>>
>> We generally don't do a clock node per clock or few clocks but rather 1
>> clock node per clock controller block. See any recent clock bindings.
>>
>> Rob
>
> Do you mean only one example is needed per clock controller block?
> cpuclk is not needed in the document?

No, I mean generally we have 1 DT node for the h/w block with all the
clock control registers rather than nodes with a single register and 1
or a couple of clocks. Sometimes the clock registers are mixed with
other functions which complicates things a bit. But I can't tell that
here because you haven't documented what's in the rest of the register
space.

Rob

2018-06-18 09:40:50

by Songjun Wu

[permalink] [raw]
Subject: Re: [PATCH 4/7] tty: serial: lantiq: Always use readl()/writel()



On 6/14/2018 6:07 PM, Arnd Bergmann wrote:
> On Tue, Jun 12, 2018 at 7:40 AM, Songjun Wu <[email protected]> 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.
>>
>> Signed-off-by: Songjun Wu <[email protected]>
> Are there any big-endian machines using this driver? The original definition
> of ltq_r32() uses non-byteswapping __raw_readl() etc, which suggests
> that the registers might be wired up in a way that matches the CPU
> endianess (this is usally a bad idea in hardware design, but nothing
> we can influence in the OS).
>
> When you change it to readl(), that will breaks all machines that rely
> on the old behavior on big-endian kernels.
>
> Arnd
It will not break existing big-endian SoC as SWAP_IO_SPACE is disabled.

Disable SWAP_IO_SPACE will not impact ltq_r32 as it uses non-byte
swapping __raw_readl() and it makes readl work in big-endian kernel too.

The old Lantiq platform enable SWAP_IO_SPACE to support PCI as it's a
little-endian bus plus PCI TX/RX swap enable impacted both data and
control path.
Alternatively PCI device driver has to do endian swap, It is better to
let PCI device driver to do endian swap instead because SWAP_IO_SPACE is
global wide macro.
Once we set it, other peripheral such as USB has to change its register
access as well


2018-06-18 09:43:13

by Songjun Wu

[permalink] [raw]
Subject: Re: [PATCH 1/7] MIPS: dts: Add aliases node for lantiq danube serial



On 6/14/2018 6:03 PM, Arnd Bergmann wrote:
> On Tue, Jun 12, 2018 at 7:40 AM, Songjun Wu <[email protected]> wrote:
>> 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 <[email protected]>
>> ---
>>
>> 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;
>> + };
>> +
> You generally want the aliases to be part of the board specific file,
> not every board numbers their serial ports in the same way.
>
> Arnd
In this chip only asc1 can be used as console,  so serial0 is defined in
chip specific file.

2018-06-18 10:07:01

by Zhu, Yi Xin

[permalink] [raw]
Subject: Re: [PATCH 2/7] clk: intel: Add clock driver for GRX500 SoC



On 6/14/2018 10:09 PM, Rob Herring wrote:
> On Thu, Jun 14, 2018 at 2:40 AM, yixin zhu <[email protected]> wrote:
>>
>>
>> On 6/13/2018 6:37 AM, Rob Herring wrote:
>>>
>>> On Tue, Jun 12, 2018 at 01:40:29PM +0800, Songjun Wu wrote:
>>>>
>>>> From: Yixin Zhu <[email protected]>
>>>>
>>>> PLL of GRX500 provide clock to DDR, CPU, and peripherals as show below
>
> [...]
>
>>>> +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";
>>>> + };
>>>
>>>
>>> We generally don't do a clock node per clock or few clocks but rather 1
>>> clock node per clock controller block. See any recent clock bindings.
>>>
>>> Rob
>>
>> Do you mean only one example is needed per clock controller block?
>> cpuclk is not needed in the document?
>
> No, I mean generally we have 1 DT node for the h/w block with all the
> clock control registers rather than nodes with a single register and 1
> or a couple of clocks. Sometimes the clock registers are mixed with
> other functions which complicates things a bit. But I can't tell that
> here because you haven't documented what's in the rest of the register
> space.
>
> Rob
>
Thanks
Will update to use one DT node for the whole clock controller.

2018-06-18 11:10:55

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 1/7] MIPS: dts: Add aliases node for lantiq danube serial

On Mon, Jun 18, 2018 at 11:42 AM, Wu, Songjun
<[email protected]> wrote:
> On 6/14/2018 6:03 PM, Arnd Bergmann wrote:
>>
>> On Tue, Jun 12, 2018 at 7:40 AM, Songjun Wu <[email protected]>
>> wrote:
>>>
>>> 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 <[email protected]>
>>> ---
>>>
>>> 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;
>>> + };
>>> +
>>
>> You generally want the aliases to be part of the board specific file,
>> not every board numbers their serial ports in the same way.
>>
>
> In this chip only asc1 can be used as console, so serial0 is defined in
> chip specific file.

This was a more general comment about 'aliases' being board specific
in principle (though we've had exceptions in the past). Even if there
is only one uart on the chip, I'd recommend following the same
conventions as the other chips that have more than one uart.

Arnd

2018-06-18 11:54:41

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 4/7] tty: serial: lantiq: Always use readl()/writel()

On Mon, Jun 18, 2018 at 11:39 AM, Wu, Songjun
<[email protected]> wrote:
>
>
> On 6/14/2018 6:07 PM, Arnd Bergmann wrote:
>>
>> On Tue, Jun 12, 2018 at 7:40 AM, Songjun Wu <[email protected]>
>> 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.
>>>
>>> Signed-off-by: Songjun Wu <[email protected]>
>>
>> Are there any big-endian machines using this driver? The original
>> definition
>> of ltq_r32() uses non-byteswapping __raw_readl() etc, which suggests
>> that the registers might be wired up in a way that matches the CPU
>> endianess (this is usally a bad idea in hardware design, but nothing
>> we can influence in the OS).
>>
>> When you change it to readl(), that will breaks all machines that rely
>> on the old behavior on big-endian kernels.
>
> It will not break existing big-endian SoC as SWAP_IO_SPACE is disabled.
>
> Disable SWAP_IO_SPACE will not impact ltq_r32 as it uses non-byte swapping
> __raw_readl() and it makes readl work in big-endian kernel too.
>
> The old Lantiq platform enable SWAP_IO_SPACE to support PCI as it's a
> little-endian bus plus PCI TX/RX swap enable impacted both data and control
> path.

Right, I see now what you mean. I was getting confused by how MIPS
defines the __raw_* accessors differently from other big-endian
architectures when CONFIG_SWAP_IO_SPACE is disabled.

I suppose this just means you can't use any PCI drivers using __raw_
accessors or memcpy_fromio(), but your patch to the serial driver is fine.

> Alternatively PCI device driver has to do endian swap, It is better to let
> PCI device driver to do endian swap instead because SWAP_IO_SPACE is global
> wide macro.
> Once we set it, other peripheral such as USB has to change its register
> access as well

I'm not entirely sure what you mean here, I would assume that aiming for
maximum compatibility with existing drivers would be the main goal here.
The USB platform drivers can already deal with being compiled for either
(or both) endianess.

Arnd

2018-06-19 06:49:32

by Songjun Wu

[permalink] [raw]
Subject: Re: [PATCH 1/7] MIPS: dts: Add aliases node for lantiq danube serial



On 6/18/2018 6:59 PM, Arnd Bergmann wrote:
> On Mon, Jun 18, 2018 at 11:42 AM, Wu, Songjun
> <[email protected]> wrote:
>> On 6/14/2018 6:03 PM, Arnd Bergmann wrote:
>>> On Tue, Jun 12, 2018 at 7:40 AM, Songjun Wu <[email protected]>
>>> wrote:
>>>> 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 <[email protected]>
>>>> ---
>>>>
>>>> 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;
>>>> + };
>>>> +
>>> You generally want the aliases to be part of the board specific file,
>>> not every board numbers their serial ports in the same way.
>>>
>> In this chip only asc1 can be used as console, so serial0 is defined in
>> chip specific file.
> This was a more general comment about 'aliases' being board specific
> in principle (though we've had exceptions in the past). Even if there
> is only one uart on the chip, I'd recommend following the same
> conventions as the other chips that have more than one uart.
>
> Arnd
Accept, 'aliases' will be move to the board specific file.