2014-06-17 15:00:17

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 00/20] ARM: sunxi: Introduce Allwinner A23 (sun8i) support

Hi everyone,

This is v2 of the patch series that introduces basic kernel support for
Allwinner's A23 SoC, which we will call the sun8i platform. This includes
basic clocks, timers, interrupts, pinctrl, and UARTs.

The series can also be found here:

https://github.com/wens/linux/tree/sunxi-a23-v2


The A23 is a mix of Allwinner's previous A20 (sun7i) and A31 (sun6i)
SoC's, but also a step forward. Most of the IP blocks are the same as
in the A31, with some features stripped out. However it has a Mali GPU,
Instead of a PowerVR.

The patches are a result of comparing the current working sun6i platform
with the A23 user manual, and various kernel and u-boot sources for A23
and A31 from Allwinner.

The series is based on v3.16-rc1, with linux-pinctrl/devel merged in for
Maxime's pinctrl external interrupts patches.

The first 12 patches are fixes, which will also be used by sun8i.
Hopefully these won't have any issues so we can get them in and fix
up some stuff queued up for 3.16.

Patch 1 adds optional support for reset controls to 8250_dw, which is
used on sun6i. The reset controls must be de-asserted for the UART to
function.

Patch 2 registers the sunxi clock gates with clkdev, so the "protect
important clock" code will work with them.

Patch 3 moves "ahb_sdram" clock protection into the protected clocks
list on sun4i, sun5i, and sun7i.

Patch 4 fixes gate indexing for sun6i PRCM APB0 gates introduced during
this cycle. The index mapping was incorrect when "clock-indicies" was
used and there were gaps between the used gates.

Patches 5~7 correct clock factor and clock rate calculations for PLL1
and PLL6 on sun6i, which have a multiplier factor starting from 1,
instead of 0 in previous SoC's.

Patch 8 renames PLL6 on sun6i to PLL6x2, to match the rate calculation
fixes in the previous patch. This patch also adds a fixed-factor clock
for PLL6, which is PLL6x2 divided by 2.

Patch 9 adds a clock driver for sun6i/sun8i MBUS clock. This clock must
be protected on sun8i or the system will hang. This series does not add
this clock to the sun6i DT.

Patch 10 adds divider table support to sunxi divider clocks. This is
used to support the AXI clock on sun8i.

The remaining patches add new support for A23 related modules.

Patch 11 adds support for the basic clock modules found on the A23.

Patches 12 and 13 add support for the PRCM clocks found on the A23,
notably the APB0 clock, which has a different divider table.

Patches 14 and 15 add the pin sets for the A23 PIO and A23 R_PIO
blocks, respectively.

Patch 16 adds A23 PRCM support to the sun6i-prcm mfd driver.
The A23 PRCM uses a slightly different subdevice list.

Patch 17 add machine support for the A23.

Patch 18 adds a Kconfig option to use R_UART as early console.

Patch 19 adds the DTSI for A23 (sun8i).

Patch 20 adds the DT for the Ippo-q8h (v5) tablet.
This tablet is one of the earliest available A23 devices.
So far we have seen 2 revisions of the mainboard inside the tablet.
The version I have is a v5, which has an unsupported SDIO WiFi chip.
The other known version uses a RTL8188 USB WiFi chip.


Greg, could you pick up the first patch? This patch is independent of
the rest. It was mostly useful to get the second UART on my tablet
working.

Emilio, Mike, patches 2~8 are fixes for existing clock drivers, 9~13
are new stuff for the A23. Please have a look.

Linus, the pinctrl patches (14 and 15) should go through your tree?

Lee, could you take patch 16, the sun6i-prcm mfd patch?

Maxime, I guess the remaining patches are for you.


Changes since v1:

- Rebased on to v3.16-rc1 with Maxime's pinctrl external interrupt
patch series

- Move devm_get_reset_control to 8250_dw main probe function and
use IF_ERR to check return values (patch 1)

- Move incorrectly squashed fixups from patch
clk: sunxi: move "ahb_sdram" to protected clock list (patch 3)
to patch
clk: sunxi: register clock gates with clkdev (patch 2)

- Add "clk: sunxi: Fix rate_recalc for sun6i PLL1" (patch 6)
(sun6i-a31-pll1 is used to support PLL5 on sun8i)

- Drop "clk: sunxi: Implement A31 PLL6 as a divs clock for 2x output"
and related DT patches;
use fixed-factor clock for PLL6 normal output, and pll6x2 as name of
the current pll6 clock. (patch 8)

- drop patches for PLL6 pre-divider for AHB1
clk: sunxi: Add support for PLL6 pre-divider on AHB1 clock
ARM: sun6i: DT: Add PLL6 pre-divider clock for AHB1 mux input

- Add support for sun6i MBUS clocks (patch 9), which is sourced from
PLL6 on sun8i by default and must be protected.

- Add support for table based divider clocks (patch 10)

- Add separate protected clock list for sun8i, and drop
clk: sunxi: add "pll6" to sun6i protected clock list (patch 11)

- Add table based sun8i-a23-axi divider clock (patch 11)

- Add A23 compatible for sun6i-a31-apb0-gates-clk (patch 13)

- Change sun8i CSI pin comments D8/D9 to SDA/SCK (patch 14)

- Document "allwinner,sun8i-a23-r-pinctrl" in
pinctrl: sunxi: Add A23 R_PIO controller support (patch 15)

- Fixed depends on for pinctrl drivers (patches 14/15)

- Add external interrupt support to pinctrl drivers patches 14/15)

- Change depends on for DEBUG_SUNXI_R_UART (patch 18)

- Dropped SMP support. I will try to work out PSCI support in u-boot

- Sort clocks by address (patch 19)

- Add PLL5 and MBUS clocks to A23 DTSI (patch 19)

- Added memory node to sun8i DTSI (patch 19)

- Added i2c2 to sun8i DTSI and DTS (patch 19)

There are a lot of changes. Hopefully I didn't miss any.

Thanks
ChenYu


Chen-Yu Tsai (20):
serial: 8250_dw: Add optional reset control support
clk: sunxi: register clock gates with clkdev
clk: sunxi: move "ahb_sdram" to protected clock list
clk: sunxi: Fix gate indexing for sun6i-a31-apb0-gates
clk: sunxi: Support factor clocks with N multiplier factor starting
from 1
clk: sunxi: Fix rate_recalc for sun6i PLL1
clk: sunxi: Fix PLL6 calculation on sun6i
ARM: sun6i: DT: Rename PLL6 to PLL6x2 and add fixed-factor-clock for
PLL6
clk: sunxi: Add sun6i MBUS clock support
clk: sunxi: Add support for table-based divider clocks
clk: sunxi: Add A23 clocks support
clk: sunxi: Add A23 APB0 support to sun6i-a31-apb0-clk
clk: sunxi: Add A23 specific compatible to sun6i-a31-apb0-gates-clk
pinctrl: sunxi: Add A23 PIO controller support
pinctrl: sunxi: Add A23 R_PIO controller support
mfd: sun6i-prcm: Add support for Allwinner A23 PRCM
ARM: sunxi: Introduce Allwinner A23 support
ARM: sunxi: Add earlyprintk support using R_UART (sun6i/sun8i)
ARM: sunxi: Add Allwinner A23 dtsi
ARM: sun8i: dt: Add Ippo-q8h v5 support

Documentation/devicetree/bindings/clock/sunxi.txt | 8 +
.../devicetree/bindings/mfd/sun6i-prcm.txt | 2 +-
.../bindings/pinctrl/allwinner,sunxi-pinctrl.txt | 2 +
.../bindings/serial/snps-dw-apb-uart.txt | 1 +
arch/arm/Kconfig.debug | 10 +
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/sun6i-a31.dtsi | 11 +-
arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts | 57 ++
arch/arm/boot/dts/sun8i-a23.dtsi | 536 +++++++++++++++++++
arch/arm/mach-sunxi/Kconfig | 8 +
arch/arm/mach-sunxi/sunxi.c | 10 +
drivers/clk/sunxi/clk-factors.c | 5 +-
drivers/clk/sunxi/clk-factors.h | 1 +
drivers/clk/sunxi/clk-sun6i-apb0-gates.c | 7 +-
drivers/clk/sunxi/clk-sun6i-apb0.c | 28 +-
drivers/clk/sunxi/clk-sunxi.c | 195 ++++++-
drivers/mfd/sun6i-prcm.c | 30 ++
drivers/pinctrl/sunxi/Kconfig | 9 +
drivers/pinctrl/sunxi/Makefile | 2 +
drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c | 142 +++++
drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c | 593 +++++++++++++++++++++
drivers/tty/serial/8250/8250_dw.c | 9 +
22 files changed, 1638 insertions(+), 30 deletions(-)
create mode 100644 arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
create mode 100644 arch/arm/boot/dts/sun8i-a23.dtsi
create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c
create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c

--
2.0.0


2014-06-17 14:53:34

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 15/20] pinctrl: sunxi: Add A23 R_PIO controller support

The A23 has a R_PIO pin controller, similar to the one found on the A31 SoC.
Add support for the pins controlled by the R_PIO controller.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
---
.../bindings/pinctrl/allwinner,sunxi-pinctrl.txt | 1 +
drivers/pinctrl/sunxi/Kconfig | 5 +
drivers/pinctrl/sunxi/Makefile | 1 +
drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c | 142 +++++++++++++++++++++
4 files changed, 149 insertions(+)
create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c

diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
index 44a78c1..93ce12e 100644
--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
@@ -14,6 +14,7 @@ Required properties:
"allwinner,sun6i-a31-r-pinctrl"
"allwinner,sun7i-a20-pinctrl"
"allwinner,sun8i-a23-pinctrl"
+ "allwinner,sun8i-a23-r-pinctrl"
- reg: Should contain the register physical address and length for the
pin controller.

diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index 7c72ed8..da49524 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -37,4 +37,9 @@ config PINCTRL_SUN8I_A23
def_bool MACH_SUN8I
select PINCTRL_SUNXI_COMMON

+config PINCTRL_SUN8I_A23_R
+ def_bool MACH_SUN8I
+ depends on RESET_CONTROLLER
+ select PINCTRL_SUNXI_COMMON
+
endif
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
index 850cd50..e797efb 100644
--- a/drivers/pinctrl/sunxi/Makefile
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_PINCTRL_SUN6I_A31) += pinctrl-sun6i-a31.o
obj-$(CONFIG_PINCTRL_SUN6I_A31_R) += pinctrl-sun6i-a31-r.o
obj-$(CONFIG_PINCTRL_SUN7I_A20) += pinctrl-sun7i-a20.o
obj-$(CONFIG_PINCTRL_SUN8I_A23) += pinctrl-sun8i-a23.o
+obj-$(CONFIG_PINCTRL_SUN8I_A23_R) += pinctrl-sun8i-a23-r.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c
new file mode 100644
index 0000000..90f3b3a
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c
@@ -0,0 +1,142 @@
+/*
+ * Allwinner A23 SoCs special pins pinctrl driver.
+ *
+ * Copyright (C) 2014 Chen-Yu Tsai
+ * Chen-Yu Tsai <[email protected]>
+ *
+ * Copyright (C) 2014 Boris Brezillon
+ * Boris Brezillon <[email protected]>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/reset.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun8i_a23_r_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_rsb"), /* SCK */
+ SUNXI_FUNCTION(0x3, "s_twi"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 0)), /* PL_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_rsb"), /* SDA */
+ SUNXI_FUNCTION(0x3, "s_twi"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 1)), /* PL_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_uart"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 2)), /* PL_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_uart"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 3)), /* PL_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_jtag"), /* MS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 4)), /* PL_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_jtag"), /* CK */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 5)), /* PL_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_jtag"), /* DO */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 6)), /* PL_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_jtag"), /* DI */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 7)), /* PL_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_twi"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 8)), /* PL_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_twi"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 9)), /* PL_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_pwm"),
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 10)), /* PL_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 11)), /* PL_EINT11 */
+};
+
+static const struct sunxi_pinctrl_desc sun8i_a23_r_pinctrl_data = {
+ .pins = sun8i_a23_r_pins,
+ .npins = ARRAY_SIZE(sun8i_a23_r_pins),
+ .pin_base = PL_BASE,
+ .irq_banks = 1,
+};
+
+static int sun8i_a23_r_pinctrl_probe(struct platform_device *pdev)
+{
+ struct reset_control *rstc;
+ int ret;
+
+ rstc = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(rstc)) {
+ dev_err(&pdev->dev, "Reset controller missing\n");
+ return PTR_ERR(rstc);
+ }
+
+ ret = reset_control_deassert(rstc);
+ if (ret)
+ return ret;
+
+ ret = sunxi_pinctrl_init(pdev,
+ &sun8i_a23_r_pinctrl_data);
+
+ if (ret)
+ reset_control_assert(rstc);
+
+ return ret;
+}
+
+static struct of_device_id sun8i_a23_r_pinctrl_match[] = {
+ { .compatible = "allwinner,sun8i-a23-r-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun8i_a23_r_pinctrl_match);
+
+static struct platform_driver sun8i_a23_r_pinctrl_driver = {
+ .probe = sun8i_a23_r_pinctrl_probe,
+ .driver = {
+ .name = "sun8i-a23-r-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = sun8i_a23_r_pinctrl_match,
+ },
+};
+module_platform_driver(sun8i_a23_r_pinctrl_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <[email protected]>");
+MODULE_AUTHOR("Boris Brezillon <[email protected]");
+MODULE_AUTHOR("Maxime Ripard <[email protected]");
+MODULE_DESCRIPTION("Allwinner A23 R_PIO pinctrl driver");
+MODULE_LICENSE("GPL");
--
2.0.0

2014-06-17 14:53:35

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 06/20] clk: sunxi: Fix rate_recalc for sun6i PLL1

PLL1 on sun6i is a factor clock with the N multiplier factor starting
from 1. Set the .n_from_one field in the clock data to match.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
drivers/clk/sunxi/clk-sunxi.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index a38c799..dc2176f 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -420,6 +420,7 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
.kwidth = 2,
.mshift = 0,
.mwidth = 2,
+ .n_from_one = 1,
};

static struct clk_factors_config sun4i_pll5_config = {
--
2.0.0

2014-06-17 14:53:32

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 20/20] ARM: sun8i: dt: Add Ippo-q8h v5 support

The Ippo-q8h is a tablet circiut board commonly found in cheap Android
tablets with A23 SoCs. There are at least 2 versions of the board, with
different peripherals, such as WiFi chips.

This patch add supports for v5 of such boards, which has a ESP8089 WiFi
chip (not supported) connected to mmc1.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts | 57 +++++++++++++++++++++++++++++
2 files changed, 59 insertions(+)
create mode 100644 arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 5986ff6..774a14b 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -380,6 +380,8 @@ dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-cubietruck.dtb \
sun7i-a20-i12-tvbox.dtb \
sun7i-a20-olinuxino-micro.dtb
+dtb-$(CONFIG_MACH_SUN8I) += \
+ sun8i-a23-ippo-q8h-v5.dtb
dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
tegra20-iris-512.dtb \
tegra20-medcom-wide.dtb \
diff --git a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
new file mode 100644
index 0000000..c1236bd
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <[email protected]>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "sun8i-a23.dtsi"
+
+/ {
+ model = "Ippo Q8H Dual Core Tablet (v5)";
+ compatible = "ippo,q8h-v5", "allwinner,sun8i-a23";
+
+ chosen {
+ bootargs = "earlyprintk console=ttyS0,115200";
+ };
+
+ soc@01c00000 {
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+ };
+
+ i2c1: i2c@01c2b000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+ };
+
+ i2c2: i2c@01c2b400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+ };
+
+ r_uart: serial@01f02800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins_a>;
+ status = "okay";
+ };
+ };
+};
+
--
2.0.0

2014-06-17 14:54:06

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 10/20] clk: sunxi: Add support for table-based divider clocks

A few of the clock modules have odd dividers, such as
the 2 lowest dividers being the same (2), or have the
same divider when the highest bit is set.

This patch adds support for optional divider tables,
so the clock framework will know about the odd values.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
drivers/clk/sunxi/clk-sunxi.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index a086b5b..7e2f015 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -703,6 +703,7 @@ struct div_data {
u8 shift;
u8 pow;
u8 width;
+ const struct clk_div_table *table;
};

static const struct div_data sun4i_axi_data __initconst = {
@@ -743,10 +744,10 @@ static void __init sunxi_divider_clk_setup(struct device_node *node,

of_property_read_string(node, "clock-output-names", &clk_name);

- clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
- reg, data->shift, data->width,
- data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
- &clk_lock);
+ clk = clk_register_divider_table(NULL, clk_name, clk_parent, 0,
+ reg, data->shift, data->width,
+ data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
+ data->table, &clk_lock);
if (clk) {
of_clk_add_provider(node, of_clk_src_simple_get, clk);
clk_register_clkdev(clk, clk_name, NULL);
--
2.0.0

2014-06-17 14:54:09

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 05/20] clk: sunxi: Support factor clocks with N multiplier factor starting from 1

The PLLs on newer Allwinner SoC's, such as the A31 and A23, have a
N multiplier factor that starts from 1, not 0.

This patch adds an option to the clock driver's config data structures
to define the difference.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
---
drivers/clk/sunxi/clk-factors.c | 5 ++++-
drivers/clk/sunxi/clk-factors.h | 1 +
2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 3806d97..399cf4d 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -62,7 +62,10 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
p = FACTOR_GET(config->pshift, config->pwidth, reg);

/* Calculate the rate */
- rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
+ if (config->n_from_one)
+ rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
+ else
+ rate = (parent_rate * n * (k + 1) >> p) / (m + 1);

return rate;
}
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
index 02e1a43..0484a48 100644
--- a/drivers/clk/sunxi/clk-factors.h
+++ b/drivers/clk/sunxi/clk-factors.h
@@ -15,6 +15,7 @@ struct clk_factors_config {
u8 mwidth;
u8 pshift;
u8 pwidth;
+ u8 n_from_one;
};

struct clk_factors {
--
2.0.0

2014-06-17 14:54:33

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 04/20] clk: sunxi: Fix gate indexing for sun6i-a31-apb0-gates

sun6i-a31-apb0-gates supports using clock-indices for holes between
individual gates. However, the driver passes the number of gates
registered in clk_data->clk_num, which of_clk_src_onecell_get uses
to recognize the range of valid indices a consumer can use.

This patch makes the driver pass the maximum gate index + 1, so
of_clk_src_onecell_get does not complain about indices greater
than gates registered.

This was tested on the A23 SoC, which has a similar APB0 clock,
but has holes for gates to removed IP blocks.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
drivers/clk/sunxi/clk-sun6i-apb0-gates.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
index 44cd27c..b342f2a 100644
--- a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
+++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
@@ -25,6 +25,7 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
void __iomem *reg;
int gate_id;
int ngates;
+ int gate_max = 0;
int i;

r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -72,9 +73,12 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
reg, gate_id,
0, NULL);
WARN_ON(IS_ERR(clk_data->clks[gate_id]));
+
+ if (gate_id > gate_max)
+ gate_max = gate_id;
}

- clk_data->clk_num = ngates;
+ clk_data->clk_num = gate_max + 1;

return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
}
--
2.0.0

2014-06-17 14:55:08

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 01/20] serial: 8250_dw: Add optional reset control support

The Allwinner A31 and A23 SoCs have a reset controller
maintaining the UART in reset by default.

This patch adds optional reset support to the driver.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt | 1 +
drivers/tty/serial/8250/8250_dw.c | 9 +++++++++
2 files changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
index f13f1c5..cb9af84 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
@@ -7,6 +7,7 @@ Required properties:
- clock-frequency : the input clock frequency for the UART.

Optional properties:
+- resets : phandle to the parent reset controller.
- reg-shift : quantity to shift the register offsets by. If this property is
not present then the register offsets are not shifted.
- reg-io-width : the size (in bytes) of the IO accesses that should be
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 51b307a..cb1b3dc 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/clk.h>
+#include <linux/reset.h>
#include <linux/pm_runtime.h>

#include <asm/byteorder.h>
@@ -59,6 +60,7 @@ struct dw8250_data {
int last_mcr;
int line;
struct clk *clk;
+ struct reset_control *rst;
struct uart_8250_dma dma;
};

@@ -408,6 +410,10 @@ static int dw8250_probe(struct platform_device *pdev)
uart.port.uartclk = clk_get_rate(data->clk);
}

+ data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
+ if (!IS_ERR(data->rst))
+ reset_control_deassert(data->rst);
+
data->dma.rx_chan_id = -1;
data->dma.tx_chan_id = -1;
data->dma.rx_param = data;
@@ -451,6 +457,9 @@ static int dw8250_remove(struct platform_device *pdev)

serial8250_unregister_port(data->line);

+ if (!IS_ERR(data->rst))
+ reset_control_assert(data->rst);
+
if (!IS_ERR(data->clk))
clk_disable_unprepare(data->clk);

--
2.0.0

2014-06-17 14:55:55

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 19/20] ARM: sunxi: Add Allwinner A23 dtsi

The Allwinner A23 is a tablet oriented SoC with 2 Cortex-A7 cores
and a Mali-400MP2 GPU.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
arch/arm/boot/dts/sun8i-a23.dtsi | 536 +++++++++++++++++++++++++++++++++++++++
1 file changed, 536 insertions(+)
create mode 100644 arch/arm/boot/dts/sun8i-a23.dtsi

diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi
new file mode 100644
index 0000000..0721a13
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a23.dtsi
@@ -0,0 +1,536 @@
+/*
+ * Copyright 2014 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <[email protected]>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ interrupt-parent = <&gic>;
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ serial4 = &uart4;
+ serial5 = &r_uart;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ memory {
+ reg = <0x40000000 0x80000000>;
+ };
+
+ pmu {
+ compatible = "arm,cortex-a7-pmu", "arm,cortex-a15-pmu";
+ interrupts = <0 120 4>,
+ <0 121 4>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ osc24M: osc24M_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+ };
+
+ osc32k: osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "osc32k";
+ };
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-a23-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+ };
+
+ pll5: clk@01c20020 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun6i-a31-pll1-clk";
+ reg = <0x01c20020 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll5";
+ };
+
+ pll6x2: clk@01c20028 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun6i-a31-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6x2";
+ };
+
+ pll6: pll6_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <2>;
+ clock-mult = <1>;
+ clocks = <&pll6x2>;
+ clock-output-names = "pll6";
+ };
+
+ cpu: cpu_clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20050 0x4>;
+
+ /*
+ * PLL1 is listed twice here.
+ * While it looks suspicious, it's actually documented
+ * that way both in the datasheet and in the code from
+ * Allwinner.
+ */
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>;
+ clock-output-names = "cpu";
+ };
+
+ axi: axi_clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-a23-axi-clk";
+ reg = <0x01c20050 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+ };
+
+ ahb1_mux: ahb1_mux_clk@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun6i-a31-ahb1-mux-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6>;
+ clock-output-names = "ahb1_mux";
+ };
+
+ ahb1: ahb1_clk@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb1_mux>;
+ clock-output-names = "ahb1";
+ };
+
+ apb1: apb1_clk@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb1>;
+ clock-output-names = "apb1";
+ };
+
+ ahb1_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun8i-a23-ahb1-gates-clk";
+ reg = <0x01c20060 0x8>;
+ clocks = <&ahb1>;
+ clock-output-names = "ahb1_mipidsi", "ahb1_dma",
+ "ahb1_mmc0", "ahb1_mmc1", "ahb1_mmc2",
+ "ahb1_nand", "ahb1_sdram",
+ "ahb1_hstimer", "ahb1_spi0",
+ "ahb1_spi1", "ahb1_otg", "ahb1_ehci",
+ "ahb1_ohci", "ahb1_ve", "ahb1_lcd",
+ "ahb1_csi", "ahb1_be", "ahb1_fe",
+ "ahb1_gpu", "ahb1_spinlock",
+ "ahb1_drc";
+ };
+
+ apb1_gates: clk@01c20068 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun8i-a23-apb1-gates-clk";
+ reg = <0x01c20068 0x4>;
+ clocks = <&apb1>;
+ clock-output-names = "apb1_codec", "apb1_pio",
+ "apb1_daudio0", "apb1_daudio1";
+ };
+
+ apb2_mux: apb2_mux@01c20058 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
+ clock-output-names = "apb2_mux";
+ };
+
+ apb2: apb2@01c20058 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun6i-a31-apb2-div-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb2_mux>;
+ clock-output-names = "apb2";
+ };
+
+ apb2_gates: clk@01c2006c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun8i-a23-apb2-gates-clk";
+ reg = <0x01c2006c 0x4>;
+ clocks = <&apb2>;
+ clock-output-names = "apb2_i2c0", "apb2_i2c1",
+ "apb2_i2c2", "apb2_uart0",
+ "apb2_uart1", "apb2_uart2",
+ "apb2_uart3", "apb2_uart4";
+ };
+
+ mmc0_clk: clk@01c20088 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20088 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "mmc0";
+ };
+
+ mmc1_clk: clk@01c2008c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2008c 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "mmc1";
+ };
+
+ mmc2_clk: clk@01c20090 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20090 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "mmc2";
+ };
+
+ spi0_clk: clk@01c200a0 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a0 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi0";
+ };
+
+ spi1_clk: clk@01c200a4 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a4 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi1";
+ };
+
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun6i-a31-mbus-clk";
+ reg = <0x01c2015c 0x4>;
+ clocks = <&osc24M>, <&pll6x2>, <&pll5>;
+ clock-output-names = "mbus";
+ };
+ };
+
+ soc@01c00000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ pio: pinctrl@01c20800 {
+ compatible = "allwinner,sun8i-a23-pinctrl";
+ reg = <0x01c20800 0x400>;
+ interrupts = <0 11 4>,
+ <0 15 4>,
+ <0 17 4>;
+ clocks = <&apb1_gates 5>;
+ gpio-controller;
+ interrupt-controller;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
+ uart0_pins_a: uart0@0 {
+ allwinner,pins = "PF2", "PF4";
+ allwinner,function = "uart0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ i2c0_pins_a: i2c0@0 {
+ allwinner,pins = "PH2", "PH3";
+ allwinner,function = "i2c0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ i2c1_pins_a: i2c1@0 {
+ allwinner,pins = "PH4", "PH5";
+ allwinner,function = "i2c1";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ i2c2_pins_a: i2c2@0 {
+ allwinner,pins = "PE12", "PE13";
+ allwinner,function = "i2c2";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ ahb1_rst: reset@01c202c0 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-ahb1-reset";
+ reg = <0x01c202c0 0xc>;
+ };
+
+ apb1_rst: reset@01c202d0 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ reg = <0x01c202d0 0x4>;
+ };
+
+ apb2_rst: reset@01c202d8 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ reg = <0x01c202d8 0x4>;
+ };
+
+ timer@01c20c00 {
+ compatible = "allwinner,sun4i-a10-timer";
+ reg = <0x01c20c00 0xa0>;
+ interrupts = <0 18 4>,
+ <0 19 4>;
+ clocks = <&osc24M>;
+ };
+
+ wdt0: watchdog@01c20ca0 {
+ compatible = "allwinner,sun6i-a31-wdt";
+ reg = <0x01c20ca0 0x20>;
+ interrupts = <0 25 4>;
+ };
+
+ uart0: serial@01c28000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28000 0x400>;
+ interrupts = <0 0 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb2_gates 16>;
+ resets = <&apb2_rst 16>;
+ status = "disabled";
+ };
+
+ uart1: serial@01c28400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28400 0x400>;
+ interrupts = <0 1 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb2_gates 17>;
+ resets = <&apb2_rst 17>;
+ status = "disabled";
+ };
+
+ uart2: serial@01c28800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28800 0x400>;
+ interrupts = <0 2 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb2_gates 18>;
+ resets = <&apb2_rst 18>;
+ status = "disabled";
+ };
+
+ uart3: serial@01c28c00 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28c00 0x400>;
+ interrupts = <0 3 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb2_gates 19>;
+ resets = <&apb2_rst 19>;
+ status = "disabled";
+ };
+
+ uart4: serial@01c29000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c29000 0x400>;
+ interrupts = <0 4 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb2_gates 20>;
+ resets = <&apb2_rst 20>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2ac00 0x400>;
+ interrupts = <0 6 4>;
+ clocks = <&apb2_gates 0>;
+ clock-frequency = <100000>;
+ resets = <&apb2_rst 0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@01c2b000 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2b000 0x400>;
+ interrupts = <0 7 4>;
+ clocks = <&apb2_gates 1>;
+ clock-frequency = <100000>;
+ resets = <&apb2_rst 1>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@01c2b400 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2b400 0x400>;
+ interrupts = <0 8 4>;
+ clocks = <&apb2_gates 2>;
+ clock-frequency = <100000>;
+ resets = <&apb2_rst 2>;
+ status = "disabled";
+ };
+
+ spi0: spi@01c68000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c68000 0x1000>;
+ interrupts = <0 65 4>;
+ clocks = <&ahb1_gates 20>, <&spi0_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 20>;
+ status = "disabled";
+ };
+
+ spi1: spi@01c69000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c69000 0x1000>;
+ interrupts = <0 66 4>;
+ clocks = <&ahb1_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 21>;
+ status = "disabled";
+ };
+
+ gic: interrupt-controller@01c81000 {
+ compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+ reg = <0x01c81000 0x1000>,
+ <0x01c82000 0x1000>,
+ <0x01c84000 0x2000>,
+ <0x01c86000 0x2000>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupts = <1 9 0xf04>;
+ };
+
+ nmi_intc: interrupt-controller@01f00c0c {
+ compatible = "allwinner,sun6i-a31-sc-nmi";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x01f00c0c 0x38>;
+ interrupts = <0 32 4>;
+ };
+
+ prcm@01f01400 {
+ compatible = "allwinner,sun8i-a23-prcm";
+ reg = <0x01f01400 0x200>;
+
+ ar100: ar100_clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&osc24M>;
+ clock-output-names = "ar100";
+ };
+
+ ahb0: ahb0_clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&ar100>;
+ clock-output-names = "ahb0";
+ };
+
+ apb0: apb0_clk {
+ compatible = "allwinner,sun8i-a23-apb0-clk";
+ #clock-cells = <0>;
+ clocks = <&ahb0>;
+ clock-output-names = "apb0";
+ };
+
+ apb0_gates: apb0_gates_clk {
+ compatible = "allwinner,sun8i-a23-apb0-gates-clk";
+ #clock-cells = <1>;
+ clocks = <&apb0>;
+ clock-indices = <0>, <2>, <3>, <4>, <6>;
+ clock-output-names = "apb0_pio", "apb0_timer",
+ "apb0_rsb", "apb0_uart",
+ "apb0_i2c";
+ };
+
+ apb0_rst: apb0_rst {
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ #reset-cells = <1>;
+ };
+ };
+
+ r_uart: serial@01f02800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01f02800 0x400>;
+ interrupts = <0 38 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb0_gates 4>;
+ resets = <&apb0_rst 4>;
+ status = "disabled";
+ };
+
+ r_pio: pinctrl@01f02c00 {
+ compatible = "allwinner,sun8i-a23-r-pinctrl";
+ reg = <0x01f02c00 0x400>;
+ interrupts = <0 45 4>;
+ clocks = <&apb0_gates 0>;
+ resets = <&apb0_rst 0>;
+ gpio-controller;
+ interrupt-controller;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
+ r_uart_pins_a: r_uart@0 {
+ allwinner,pins = "PL2", "PL3";
+ allwinner,function = "s_uart";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ };
+ };
+};
--
2.0.0

2014-06-17 14:54:04

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 03/20] clk: sunxi: move "ahb_sdram" to protected clock list

With sunxi_gates clocks registered with clkdev, we can use the
protected clocks list to enable the "ahb_sdram" clock, instead
of looking for it and adding CLK_IGNORE_UNUSED inline in the
clock setup code.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
drivers/clk/sunxi/clk-sunxi.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index e43ed6a..a38c799 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -870,7 +870,6 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
int qty;
int i = 0;
int j = 0;
- int ignore;

reg = of_iomap(node, 0);

@@ -891,11 +890,8 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
of_property_read_string_index(node, "clock-output-names",
j, &clk_name);

- /* No driver claims this clock, but it should remain gated */
- ignore = !strcmp("ahb_sdram", clk_name) ? CLK_IGNORE_UNUSED : 0;
-
clk_data->clks[i] = clk_register_gate(NULL, clk_name,
- clk_parent, ignore,
+ clk_parent, 0,
reg + 4 * (i/32), i % 32,
0, &clk_lock);
WARN_ON(IS_ERR(clk_data->clks[i]));
@@ -1203,6 +1199,7 @@ static void __init sunxi_init_clocks(const char *clocks[], int nclocks)

static const char *sun4i_a10_critical_clocks[] __initdata = {
"pll5_ddr",
+ "ahb_sdram",
};

static void __init sun4i_a10_init_clocks(struct device_node *node)
@@ -1215,6 +1212,7 @@ CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks)
static const char *sun5i_critical_clocks[] __initdata = {
"mbus",
"pll5_ddr",
+ "ahb_sdram",
};

static void __init sun5i_init_clocks(struct device_node *node)
--
2.0.0

2014-06-17 14:56:31

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 18/20] ARM: sunxi: Add earlyprintk support using R_UART (sun6i/sun8i)

sun6i/sun8i have a UART in the RTC block group, which can be used
as an early console. This is most useful on sun8i as UART0 is muxed
with MMC0, which is not available if we boot from MMC.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
arch/arm/Kconfig.debug | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 8f90595..3548612 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -715,6 +715,14 @@ choice
Say Y here if you want kernel low-level debugging support
on Allwinner A1X based platforms on the UART1.

+ config DEBUG_SUNXI_R_UART
+ bool "Kernel low-level debugging messages via sunXi R_UART"
+ depends on MACH_SUN6I || MACH_SUN8I
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ on Allwinner A31/A23 based platforms on the R_UART.
+
config TEGRA_DEBUG_UART_AUTO_ODMDATA
bool "Kernel low-level debugging messages via Tegra UART via ODMDATA"
depends on ARCH_TEGRA
@@ -1043,6 +1051,7 @@ config DEBUG_UART_PHYS
default 0x01c28400 if DEBUG_SUNXI_UART1
default 0x01d0c000 if DEBUG_DAVINCI_DA8XX_UART1
default 0x01d0d000 if DEBUG_DAVINCI_DA8XX_UART2
+ default 0x01f02800 if DEBUG_SUNXI_R_UART
default 0x02530c00 if DEBUG_KEYSTONE_UART0
default 0x02531000 if DEBUG_KEYSTONE_UART1
default 0x03010fe0 if ARCH_RPC
@@ -1118,6 +1127,7 @@ config DEBUG_UART_VIRT
default 0xf1600000 if ARCH_INTEGRATOR
default 0xf1c28000 if DEBUG_SUNXI_UART0
default 0xf1c28400 if DEBUG_SUNXI_UART1
+ default 0xf1f02800 if DEBUG_SUNXI_R_UART
default 0xf2100000 if DEBUG_PXA_UART1
default 0xf4090000 if ARCH_LPC32XX
default 0xf4200000 if ARCH_GEMINI
--
2.0.0

2014-06-17 14:56:32

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 07/20] clk: sunxi: Fix PLL6 calculation on sun6i

The N factor for PLL6 counts from 1 to 32, as specified in the A23
manual, and shown in Allwinner's original code.

Also the PLL6 factors calculate the clock rate for PLL6x2, not the
normal halved output for PLL6. This is what the factors clk
.recalc_rate callback expects.

This patch fixes the N factor in the clock driver, calculates the
rate for PLL6x2, and fixes the comment describing it.

A further patch (to the DT) should add a fixed-factor /2 clock as
the normally used PLL6 output.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
---
drivers/clk/sunxi/clk-sunxi.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index dc2176f..eca3c6e 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -196,9 +196,9 @@ static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate,
}

/**
- * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6
- * PLL6 rate is calculated as follows
- * rate = parent_rate * n * (k + 1) / 2
+ * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6 (x2)
+ * PLL6 (x2) rate is calculated as follows
+ * rate = parent_rate * (n + 1) * (k + 1)
* parent_rate is always 24Mhz
*/

@@ -207,13 +207,7 @@ static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate,
{
u8 div;

- /*
- * We always have 24MHz / 2, so we can just say that our
- * parent clock is 12MHz.
- */
- parent_rate = parent_rate / 2;
-
- /* Normalize value to a parent_rate multiple (24M / 2) */
+ /* Normalize value to a parent_rate multiple (24M) */
div = *freq / parent_rate;
*freq = parent_rate * div;

@@ -225,7 +219,7 @@ static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate,
if (*k > 3)
*k = 3;

- *n = DIV_ROUND_UP(div, (*k+1));
+ *n = DIV_ROUND_UP(div, (*k+1)) - 1;
}

/**
@@ -435,6 +429,7 @@ static struct clk_factors_config sun6i_a31_pll6_config = {
.nwidth = 5,
.kshift = 4,
.kwidth = 2,
+ .n_from_one = 1,
};

static struct clk_factors_config sun4i_apb1_config = {
--
2.0.0

2014-06-17 14:56:29

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 11/20] clk: sunxi: Add A23 clocks support

The clock control unit on the A23 is similar to the one found on the A31.

The AHB1, APB1, APB2 gates on the A23 are almost identical to the ones
on the A31, but some outputs are missing.

The main CPU PLL (PLL1) however is like that on older Allwinner SoCs, such
as the A10 or A20, but the N factor starts from 1 instead of 0.

This patch adds support for PLL1 and all the basic clock gates.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 5 +
drivers/clk/sunxi/clk-sunxi.c | 115 ++++++++++++++++++++++
2 files changed, 120 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 7b2ba41..af9e47d 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -9,11 +9,13 @@ Required properties:
"allwinner,sun4i-a10-osc-clk" - for a gatable oscillator
"allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
+ "allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23
"allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
"allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
"allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
"allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
"allwinner,sun4i-a10-axi-clk" - for the AXI clock
+ "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23
"allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
"allwinner,sun4i-a10-ahb-clk" - for the AHB clock
"allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10
@@ -23,6 +25,7 @@ Required properties:
"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
"allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
+ "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
"allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
"allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
"allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
@@ -37,8 +40,10 @@ Required properties:
"allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
"allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
"allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
+ "allwinner,sun8i-a23-apb1-gates-clk" - for the APB1 gates on A23
"allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
+ "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
"allwinner,sun6i-a31-mbus-clk" - for the MBUS clocks on A31 / A23
"allwinner,sun7i-a20-out-clk" - for the external output clocks
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 7e2f015..f418392 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -164,6 +164,54 @@ static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate,
}

/**
+ * sun8i_a23_get_pll1_factors() - calculates n, k, m, p factors for PLL1
+ * PLL1 rate is calculated as follows
+ * rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
+ * parent_rate is always 24Mhz
+ */
+
+static void sun8i_a23_get_pll1_factors(u32 *freq, u32 parent_rate,
+ u8 *n, u8 *k, u8 *m, u8 *p)
+{
+ u8 div;
+
+ /* Normalize value to a 6M multiple */
+ div = *freq / 6000000;
+ *freq = 6000000 * div;
+
+ /* we were called to round the frequency, we can now return */
+ if (n == NULL)
+ return;
+
+ /* m is always zero for pll1 */
+ *m = 0;
+
+ /* k is 1 only on these cases */
+ if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000)
+ *k = 1;
+ else
+ *k = 0;
+
+ /* p will be 2 for divs under 20 and odd divs under 32 */
+ if (div < 20 || (div < 32 && (div & 1)))
+ *p = 2;
+
+ /* p will be 1 for even divs under 32, divs under 40 and odd pairs
+ * of divs between 40-62 */
+ else if (div < 40 || (div < 64 && (div & 2)))
+ *p = 1;
+
+ /* any other entries have p = 0 */
+ else
+ *p = 0;
+
+ /* calculate a suitable n based on k and p */
+ div <<= *p;
+ div /= (*k + 1);
+ *n = div / 4 - 1;
+}
+
+/**
* sun4i_get_pll5_factors() - calculates n, k factors for PLL5
* PLL5 rate is calculated as follows
* rate = parent_rate * n * (k + 1)
@@ -448,6 +496,18 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
.n_from_one = 1,
};

+static struct clk_factors_config sun8i_a23_pll1_config = {
+ .nshift = 8,
+ .nwidth = 5,
+ .kshift = 4,
+ .kwidth = 2,
+ .mshift = 0,
+ .mwidth = 2,
+ .pshift = 16,
+ .pwidth = 2,
+ .n_from_one = 1,
+};
+
static struct clk_factors_config sun4i_pll5_config = {
.nshift = 8,
.nwidth = 5,
@@ -503,6 +563,12 @@ static const struct factors_data sun6i_a31_pll1_data __initconst = {
.getter = sun6i_a31_get_pll1_factors,
};

+static const struct factors_data sun8i_a23_pll1_data __initconst = {
+ .enable = 31,
+ .table = &sun8i_a23_pll1_config,
+ .getter = sun8i_a23_get_pll1_factors,
+};
+
static const struct factors_data sun7i_a20_pll4_data __initconst = {
.enable = 31,
.table = &sun4i_pll5_config,
@@ -712,6 +778,25 @@ static const struct div_data sun4i_axi_data __initconst = {
.width = 2,
};

+static const struct clk_div_table sun8i_a23_axi_table[] __initconst = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 3 },
+ { .val = 3, .div = 4 },
+ { .val = 4, .div = 4 },
+ { .val = 5, .div = 4 },
+ { .val = 6, .div = 4 },
+ { .val = 7, .div = 4 },
+ { } /* sentinel */
+};
+
+static const struct div_data sun8i_a23_axi_data __initconst = {
+ .shift = 0,
+ .pow = 0,
+ .width = 8,
+ .table = sun8i_a23_axi_table,
+};
+
static const struct div_data sun4i_ahb_data __initconst = {
.shift = 4,
.pow = 1,
@@ -844,6 +929,10 @@ static const struct gates_data sun7i_a20_ahb_gates_data __initconst = {
.mask = { 0x12f77fff, 0x16ff3f },
};

+static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = {
+ .mask = {0x25386742, 0x2505111},
+};
+
static const struct gates_data sun4i_apb0_gates_data __initconst = {
.mask = {0x4EF},
};
@@ -876,6 +965,10 @@ static const struct gates_data sun6i_a31_apb1_gates_data __initconst = {
.mask = {0x3031},
};

+static const struct gates_data sun8i_a23_apb1_gates_data __initconst = {
+ .mask = {0x3021},
+};
+
static const struct gates_data sun6i_a31_apb2_gates_data __initconst = {
.mask = {0x3F000F},
};
@@ -884,6 +977,10 @@ static const struct gates_data sun7i_a20_apb1_gates_data __initconst = {
.mask = { 0xff80ff },
};

+static const struct gates_data sun8i_a23_apb2_gates_data __initconst = {
+ .mask = {0x1F0007},
+};
+
static const struct gates_data sun4i_a10_usb_gates_data __initconst = {
.mask = {0x1C0},
.reset_mask = 0x07,
@@ -1139,6 +1236,7 @@ free_clkdata:
static const struct of_device_id clk_factors_match[] __initconst = {
{.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,},
{.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
+ {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,},
{.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,},
{.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
{.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
@@ -1151,6 +1249,7 @@ static const struct of_device_id clk_factors_match[] __initconst = {
/* Matches for divider clocks */
static const struct of_device_id clk_div_match[] __initconst = {
{.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,},
+ {.compatible = "allwinner,sun8i-a23-axi-clk", .data = &sun8i_a23_axi_data,},
{.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,},
{.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,},
{.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
@@ -1180,6 +1279,7 @@ static const struct of_device_id clk_gates_match[] __initconst = {
{.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
{.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
{.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
+ {.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,},
{.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
{.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
{.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
@@ -1189,7 +1289,9 @@ static const struct of_device_id clk_gates_match[] __initconst = {
{.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
{.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
{.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
+ {.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,},
{.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
+ {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,},
{.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
{.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,},
{.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,},
@@ -1276,3 +1378,16 @@ static void __init sun6i_init_clocks(struct device_node *node)
ARRAY_SIZE(sun6i_critical_clocks));
}
CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
+
+static const char *sun8i_critical_clocks[] __initdata = {
+ "cpu",
+ "ahb1_sdram",
+ "mbus",
+};
+
+static void __init sun8i_init_clocks(void)
+{
+ sunxi_init_clocks(sun8i_critical_clocks,
+ ARRAY_SIZE(sun8i_critical_clocks));
+}
+CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun8i_init_clocks);
--
2.0.0

2014-06-17 14:53:31

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 02/20] clk: sunxi: register clock gates with clkdev

The new important clock protect code requires the clocks be
registered with clkdev. This was missing for sunxi_gates
type clocks.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
---
drivers/clk/sunxi/clk-sunxi.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index fb2ce84..e43ed6a 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -899,6 +899,7 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
reg + 4 * (i/32), i % 32,
0, &clk_lock);
WARN_ON(IS_ERR(clk_data->clks[i]));
+ clk_register_clkdev(clk_data->clks[i], clk_name, NULL);

j++;
}
--
2.0.0

2014-06-17 14:53:29

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 13/20] clk: sunxi: Add A23 specific compatible to sun6i-a31-apb0-gates-clk

The sun6i-a31-apb0-gates-clk driver is generic in that it supports
the "clock-indicies" DT property with "clock-output-names" to list
the valid clock gate bits.

However this might lead one to assume that the clock in the A23 is
the same as the A31. To make it clear, we add a new compatible for
the A23, "allwinner,sun8i-a23-apb0-gates-clk".

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/clk-sun6i-apb0-gates.c | 1 +
2 files changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index e3a47ec..ad446b2 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -34,6 +34,7 @@ Required properties:
"allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
"allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31
"allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
+ "allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23
"allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
"allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing
"allwinner,sun4i-a10-apb1-gates-clk" - for the APB1 gates on A10
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
index b342f2a..f147fee 100644
--- a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
+++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
@@ -85,6 +85,7 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)

const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = {
{ .compatible = "allwinner,sun6i-a31-apb0-gates-clk" },
+ { .compatible = "allwinner,sun8i-a23-apb0-gates-clk" },
{ /* sentinel */ }
};

--
2.0.0

2014-06-17 14:57:44

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 12/20] clk: sunxi: Add A23 APB0 support to sun6i-a31-apb0-clk

The A23 has an almost identical PRCM clock tree. The difference in
the APB0 clock is the smallest divisor is 1, instead of 2.

This patch extends the sun6i-a31-apb0-clk driver to take divider
tables associated to compatibles, and adds a compatible for the A23
variant.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/clk-sun6i-apb0.c | 28 ++++++++++++++++++-----
2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index af9e47d..e3a47ec 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -28,6 +28,7 @@ Required properties:
"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
"allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
"allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
+ "allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23
"allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
"allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
"allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c
index 11f17c3..2197ac7 100644
--- a/drivers/clk/sunxi/clk-sun6i-apb0.c
+++ b/drivers/clk/sunxi/clk-sun6i-apb0.c
@@ -11,6 +11,7 @@
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>

/*
@@ -28,6 +29,21 @@ static const struct clk_div_table sun6i_a31_apb0_divs[] = {
{ /* sentinel */ },
};

+/* The A23 APB0 clock has a standard power of 2 divisor */
+static const struct clk_div_table sun8i_a23_apb0_divs[] = {
+ { .val = 0, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 2, .div = 4, },
+ { .val = 3, .div = 8, },
+ { /* sentinel */ },
+};
+
+const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-apb0-clk", .data = &sun6i_a31_apb0_divs },
+ { .compatible = "allwinner,sun8i-a23-apb0-clk", .data = &sun8i_a23_apb0_divs },
+ { /* sentinel */ }
+};
+
static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -36,12 +52,17 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
struct resource *r;
void __iomem *reg;
struct clk *clk;
+ const struct of_device_id *device;

r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(reg))
return PTR_ERR(reg);

+ device = of_match_device(sun6i_a31_apb0_clk_dt_ids, &pdev->dev);
+ if (!device)
+ return -EINVAL;
+
clk_parent = of_clk_get_parent_name(np, 0);
if (!clk_parent)
return -EINVAL;
@@ -49,7 +70,7 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
of_property_read_string(np, "clock-output-names", &clk_name);

clk = clk_register_divider_table(&pdev->dev, clk_name, clk_parent,
- 0, reg, 0, 2, 0, sun6i_a31_apb0_divs,
+ 0, reg, 0, 2, 0, device->data,
NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
@@ -57,11 +78,6 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
return of_clk_add_provider(np, of_clk_src_simple_get, clk);
}

-const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = {
- { .compatible = "allwinner,sun6i-a31-apb0-clk" },
- { /* sentinel */ }
-};
-
static struct platform_driver sun6i_a31_apb0_clk_driver = {
.driver = {
.name = "sun6i-a31-apb0-clk",
--
2.0.0

2014-06-17 14:58:03

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 09/20] clk: sunxi: Add sun6i MBUS clock support

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/clk-sunxi.c | 44 +++++++++++++++++++++++
2 files changed, 45 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index b9ec668..7b2ba41 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -40,6 +40,7 @@ Required properties:
"allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
+ "allwinner,sun6i-a31-mbus-clk" - for the MBUS clocks on A31 / A23
"allwinner,sun7i-a20-out-clk" - for the external output clocks
"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index eca3c6e..a086b5b 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -307,6 +307,37 @@ static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate,


/**
+ * sun6i_a31_get_mbus_factors() - calculates m factor for MBUS clocks
+ * MBUS rate is calculated as follows
+ * rate = parent_rate / (m + 1);
+ */
+
+static void sun6i_a31_get_mbus_factors(u32 *freq, u32 parent_rate,
+ u8 *n, u8 *k, u8 *m, u8 *p)
+{
+ u8 div;
+
+ /* These clocks can only divide, so we will never be able to achieve
+ * frequencies higher than the parent frequency */
+ if (*freq > parent_rate)
+ *freq = parent_rate;
+
+ div = DIV_ROUND_UP(parent_rate, *freq);
+
+ if (div > 8)
+ div = 8;
+
+ *freq = parent_rate / div;
+
+ /* we were called to round the frequency, we can now return */
+ if (n == NULL)
+ return;
+
+ *m = div - 1;
+}
+
+
+/**
* sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B
* CLK_OUT rate is calculated as follows
* rate = (parent_rate >> p) / (m + 1);
@@ -447,6 +478,11 @@ static struct clk_factors_config sun4i_mod0_config = {
.pwidth = 2,
};

+static struct clk_factors_config sun6i_a31_mbus_config = {
+ .mshift = 0,
+ .mwidth = 3,
+};
+
/* user manual says "n" but it's really "p" */
static struct clk_factors_config sun7i_a20_out_config = {
.mshift = 8,
@@ -505,6 +541,13 @@ static const struct factors_data sun4i_mod0_data __initconst = {
.getter = sun4i_get_mod0_factors,
};

+static const struct factors_data sun6i_a31_mbus_data __initconst = {
+ .enable = 31,
+ .mux = 24,
+ .table = &sun6i_a31_mbus_config,
+ .getter = sun6i_a31_get_mbus_factors,
+};
+
static const struct factors_data sun7i_a20_out_data __initconst = {
.enable = 31,
.mux = 24,
@@ -1099,6 +1142,7 @@ static const struct of_device_id clk_factors_match[] __initconst = {
{.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
{.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
{.compatible = "allwinner,sun4i-a10-mod0-clk", .data = &sun4i_mod0_data,},
+ {.compatible = "allwinner,sun6i-a31-mbus-clk", .data = &sun6i_a31_mbus_data,},
{.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},
{}
};
--
2.0.0

2014-06-17 14:58:27

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 17/20] ARM: sunxi: Introduce Allwinner A23 support

The Allwinner A23 is a dual-core Cortex-A7-based SoC. It re-uses most of
the IPs found in previous SoCs, notably the A31.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
arch/arm/mach-sunxi/Kconfig | 8 ++++++++
arch/arm/mach-sunxi/sunxi.c | 10 ++++++++++
2 files changed, 18 insertions(+)

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 0fbd4f1..6434e3b 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -35,4 +35,12 @@ config MACH_SUN7I
select HAVE_ARM_ARCH_TIMER
select SUN5I_HSTIMER

+config MACH_SUN8I
+ bool "Allwinner A23 (sun8i) SoCs support"
+ default ARCH_SUNXI
+ select ARCH_HAS_RESET_CONTROLLER
+ select ARM_GIC
+ select MFD_SUN6I_PRCM
+ select RESET_CONTROLLER
+
endif
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
index 3f9587b..962ff30 100644
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -53,3 +53,13 @@ static const char * const sun7i_board_dt_compat[] = {
DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family")
.dt_compat = sun7i_board_dt_compat,
MACHINE_END
+
+static const char * const sun8i_board_dt_compat[] = {
+ "allwinner,sun8i-a23",
+ NULL,
+};
+
+DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family")
+ .init_time = sun6i_timer_init,
+ .dt_compat = sun8i_board_dt_compat,
+MACHINE_END
--
2.0.0

2014-06-17 14:58:46

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 16/20] mfd: sun6i-prcm: Add support for Allwinner A23 PRCM

The Allwinner A23 SoC has a PRCM unit like the previous A31 SoC.
The differences are the AR100 clock can no longer be modified,
the APB0 clock has different divisors, and some clock gates are
gone.

This patch adds a compatible with a modified subdevice list for
the A23.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
.../devicetree/bindings/mfd/sun6i-prcm.txt | 2 +-
drivers/mfd/sun6i-prcm.c | 30 ++++++++++++++++++++++
2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt b/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt
index 1f5a31f..03c5a55 100644
--- a/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt
+++ b/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt
@@ -4,7 +4,7 @@ PRCM is an MFD device exposing several Power Management related devices
(like clks and reset controllers).

Required properties:
- - compatible: "allwinner,sun6i-a31-prcm"
+ - compatible: "allwinner,sun6i-a31-prcm" or "allwinner,sun8i-a23-prcm"
- reg: The PRCM registers range

The prcm node may contain several subdevices definitions:
diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c
index 718fc4d..7a198d3 100644
--- a/drivers/mfd/sun6i-prcm.c
+++ b/drivers/mfd/sun6i-prcm.c
@@ -76,16 +76,46 @@ static const struct mfd_cell sun6i_a31_prcm_subdevs[] = {
},
};

+static const struct mfd_cell sun8i_a23_prcm_subdevs[] = {
+ {
+ .name = "sun6i-a31-apb0-clk",
+ .of_compatible = "allwinner,sun8i-a23-apb0-clk",
+ .num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res),
+ .resources = sun6i_a31_apb0_clk_res,
+ },
+ {
+ .name = "sun6i-a31-apb0-gates-clk",
+ .of_compatible = "allwinner,sun8i-a23-apb0-gates-clk",
+ .num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res),
+ .resources = sun6i_a31_apb0_gates_clk_res,
+ },
+ {
+ .name = "sun6i-a31-apb0-clock-reset",
+ .of_compatible = "allwinner,sun6i-a31-clock-reset",
+ .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
+ .resources = sun6i_a31_apb0_rstc_res,
+ },
+};
+
static const struct prcm_data sun6i_a31_prcm_data = {
.nsubdevs = ARRAY_SIZE(sun6i_a31_prcm_subdevs),
.subdevs = sun6i_a31_prcm_subdevs,
};

+static const struct prcm_data sun8i_a23_prcm_data = {
+ .nsubdevs = ARRAY_SIZE(sun8i_a23_prcm_subdevs),
+ .subdevs = sun8i_a23_prcm_subdevs,
+};
+
static const struct of_device_id sun6i_prcm_dt_ids[] = {
{
.compatible = "allwinner,sun6i-a31-prcm",
.data = &sun6i_a31_prcm_data,
},
+ {
+ .compatible = "allwinner,sun8i-a23-prcm",
+ .data = &sun8i_a23_prcm_data,
+ },
{ /* sentinel */ },
};

--
2.0.0

2014-06-17 14:58:44

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 08/20] ARM: sun6i: DT: Rename PLL6 to PLL6x2 and add fixed-factor-clock for PLL6

The PLL6 clock driver actually manages the PLL6x2 output of PLL6, so
rename the node accordingly, and add a halved fixed-factor-clock for
normal PLL6 output used by most modules.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
arch/arm/boot/dts/sun6i-a31.dtsi | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index a9dfa12..12d558b 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -94,11 +94,20 @@
clock-output-names = "pll1";
};

- pll6: clk@01c20028 {
+ pll6x2: clk@01c20028 {
#clock-cells = <0>;
compatible = "allwinner,sun6i-a31-pll6-clk";
reg = <0x01c20028 0x4>;
clocks = <&osc24M>;
+ clock-output-names = "pll6x2";
+ };
+
+ pll6: pll6_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <2>;
+ clock-mult = <1>;
+ clocks = <&pll6x2>;
clock-output-names = "pll6";
};

--
2.0.0

2014-06-17 14:59:22

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 14/20] pinctrl: sunxi: Add A23 PIO controller support

The A23 uses the same pin controller as previous SoC's from Allwinner.
Add support for the pins controlled by the main PIO controller.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
---
.../bindings/pinctrl/allwinner,sunxi-pinctrl.txt | 1 +
drivers/pinctrl/sunxi/Kconfig | 4 +
drivers/pinctrl/sunxi/Makefile | 1 +
drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c | 593 +++++++++++++++++++++
4 files changed, 599 insertions(+)
create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c

diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
index d8d0656..44a78c1 100644
--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
@@ -13,6 +13,7 @@ Required properties:
"allwinner,sun6i-a31-pinctrl"
"allwinner,sun6i-a31-r-pinctrl"
"allwinner,sun7i-a20-pinctrl"
+ "allwinner,sun8i-a23-pinctrl"
- reg: Should contain the register physical address and length for the
pin controller.

diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index 73e0a30..7c72ed8 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -33,4 +33,8 @@ config PINCTRL_SUN7I_A20
def_bool PINCTRL_SUNXI || MACH_SUN7I
select PINCTRL_SUNXI_COMMON

+config PINCTRL_SUN8I_A23
+ def_bool MACH_SUN8I
+ select PINCTRL_SUNXI_COMMON
+
endif
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
index 0f4461c..850cd50 100644
--- a/drivers/pinctrl/sunxi/Makefile
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_PINCTRL_SUN5I_A13) += pinctrl-sun5i-a13.o
obj-$(CONFIG_PINCTRL_SUN6I_A31) += pinctrl-sun6i-a31.o
obj-$(CONFIG_PINCTRL_SUN6I_A31_R) += pinctrl-sun6i-a31-r.o
obj-$(CONFIG_PINCTRL_SUN7I_A20) += pinctrl-sun7i-a20.o
+obj-$(CONFIG_PINCTRL_SUN8I_A23) += pinctrl-sun8i-a23.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
new file mode 100644
index 0000000..ac71e8c
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
@@ -0,0 +1,593 @@
+/*
+ * Allwinner A23 SoCs pinctrl driver.
+ *
+ * Copyright (C) 2014 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <[email protected]>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ *
+ * Maxime Ripard <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun8i_a23_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* CS */
+ SUNXI_FUNCTION(0x3, "jtag"), /* MS0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 0)), /* PA_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* CLK */
+ SUNXI_FUNCTION(0x3, "jtag"), /* CKO */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 1)), /* PA_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */
+ SUNXI_FUNCTION(0x3, "jtag"), /* DOO */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 2)), /* PA_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* MISO */
+ SUNXI_FUNCTION(0x3, "jtag"), /* DIO */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 3)), /* PA_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 4)), /* PA_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 5)), /* PA_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 6)), /* PA_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 7)), /* PA_EINT7 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 0)), /* PB_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 1)), /* PB_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 2)), /* PB_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 3)), /* PB_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* SYNC */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 4)), /* PB_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* DOUT */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 5)), /* PB_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* DIN */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 6)), /* PB_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "i2s0"), /* DI */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 7)), /* PB_EINT7 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* WE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* ALE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MISO */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* CLE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* CE1 */
+ SUNXI_FUNCTION(0x3, "spi0")), /* CS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* CE0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* RE */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* RB0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* RB1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ2 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ3 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ4 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ5 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand"), /* DQ6 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand"), /* DQ7 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand"), /* DQS */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* RST */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* CE2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* CE3 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* CMD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D8 */
+ SUNXI_FUNCTION(0x3, "uart3")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D9 */
+ SUNXI_FUNCTION(0x3, "uart3")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */
+ SUNXI_FUNCTION(0x3, "uart1")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */
+ SUNXI_FUNCTION(0x3, "uart1")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */
+ SUNXI_FUNCTION(0x3, "uart1")), /* RTS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */
+ SUNXI_FUNCTION(0x3, "uart1")), /* CTS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */
+ SUNXI_FUNCTION(0x3, "i2s1")), /* SYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */
+ SUNXI_FUNCTION(0x3, "i2s1")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D16 */
+ SUNXI_FUNCTION(0x3, "i2s1")), /* DOUT */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D17 */
+ SUNXI_FUNCTION(0x3, "i2s1")), /* DIN */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VPC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* DE */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN3 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* PCLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* MCLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* HSYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* VSYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* SCK */
+ SUNXI_FUNCTION(0x3, "i2c2")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* SDA */
+ SUNXI_FUNCTION(0x3, "i2c2")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* MS1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DI1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart0")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DO1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "uart0")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* CK1 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 0)), /* PG_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 1)), /* PG_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 2)), /* PG_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 3)), /* PG_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 4)), /* PG_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 5)), /* PG_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 6)), /* PG_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 7)), /* PG_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 8)), /* PG_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 9)), /* PG_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* SYNC */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 10)), /* PG_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 11)), /* PG_EINT11 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* DOUT */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 12)), /* PG_EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* DIN */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 13)), /* PG_EINT13 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm0")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm1")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* CS */
+ SUNXI_FUNCTION(0x3, "uart3")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart3")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* DOUT */
+ SUNXI_FUNCTION(0x3, "uart3")), /* RTS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* DIN */
+ SUNXI_FUNCTION(0x3, "uart3")), /* CTS */
+};
+
+static const struct sunxi_pinctrl_desc sun8i_a23_pinctrl_data = {
+ .pins = sun8i_a23_pins,
+ .npins = ARRAY_SIZE(sun8i_a23_pins),
+ .irq_banks = 3,
+};
+
+static int sun8i_a23_pinctrl_probe(struct platform_device *pdev)
+{
+ return sunxi_pinctrl_init(pdev,
+ &sun8i_a23_pinctrl_data);
+}
+
+static struct of_device_id sun8i_a23_pinctrl_match[] = {
+ { .compatible = "allwinner,sun8i-a23-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun8i_a23_pinctrl_match);
+
+static struct platform_driver sun8i_a23_pinctrl_driver = {
+ .probe = sun8i_a23_pinctrl_probe,
+ .driver = {
+ .name = "sun8i-a23-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = sun8i_a23_pinctrl_match,
+ },
+};
+module_platform_driver(sun8i_a23_pinctrl_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <[email protected]>");
+MODULE_AUTHOR("Maxime Ripard <[email protected]");
+MODULE_DESCRIPTION("Allwinner A23 pinctrl driver");
+MODULE_LICENSE("GPL");
--
2.0.0

2014-06-17 21:23:27

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH v2 05/20] clk: sunxi: Support factor clocks with N multiplier factor starting from 1

On Tue, Jun 17, 2014 at 9:52 AM, Chen-Yu Tsai <[email protected]> wrote:
> The PLLs on newer Allwinner SoC's, such as the A31 and A23, have a
> N multiplier factor that starts from 1, not 0.
>
> This patch adds an option to the clock driver's config data structures
> to define the difference.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> Acked-by: Maxime Ripard <[email protected]>
> ---
> drivers/clk/sunxi/clk-factors.c | 5 ++++-
> drivers/clk/sunxi/clk-factors.h | 1 +
> 2 files changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
> index 3806d97..399cf4d 100644
> --- a/drivers/clk/sunxi/clk-factors.c
> +++ b/drivers/clk/sunxi/clk-factors.c
> @@ -62,7 +62,10 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
> p = FACTOR_GET(config->pshift, config->pwidth, reg);
>
> /* Calculate the rate */
> - rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
> + if (config->n_from_one)
> + rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
> + else
> + rate = (parent_rate * n * (k + 1) >> p) / (m + 1);

This can be simplified and support any base with:

rate = (parent_rate * (n + config->n_base) * (k + 1) >> p) / (m + 1);

2014-06-18 08:30:08

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCH v2 16/20] mfd: sun6i-prcm: Add support for Allwinner A23 PRCM

> The Allwinner A23 SoC has a PRCM unit like the previous A31 SoC.
> The differences are the AR100 clock can no longer be modified,
> the APB0 clock has different divisors, and some clock gates are
> gone.
>
> This patch adds a compatible with a modified subdevice list for
> the A23.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> ---
> .../devicetree/bindings/mfd/sun6i-prcm.txt | 2 +-
> drivers/mfd/sun6i-prcm.c | 30 ++++++++++++++++++++++
> 2 files changed, 31 insertions(+), 1 deletion(-)

The patch looks fine to me, but I'm concerned about the size of the
patch set and the amount of subsystems it touches.

I am guessing that this patch can just be taken independently though.
Please correct me if I'm wrong.

--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

2014-06-18 09:10:20

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 01/20] serial: 8250_dw: Add optional reset control support

On Tue, Jun 17, 2014 at 10:52:38PM +0800, Chen-Yu Tsai wrote:
> The Allwinner A31 and A23 SoCs have a reset controller
> maintaining the UART in reset by default.
>
> This patch adds optional reset support to the driver.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (447.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 09:15:53

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 03/20] clk: sunxi: move "ahb_sdram" to protected clock list

On Tue, Jun 17, 2014 at 10:52:40PM +0800, Chen-Yu Tsai wrote:
> With sunxi_gates clocks registered with clkdev, we can use the
> protected clocks list to enable the "ahb_sdram" clock, instead
> of looking for it and adding CLK_IGNORE_UNUSED inline in the
> clock setup code.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (500.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 09:40:18

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 04/20] clk: sunxi: Fix gate indexing for sun6i-a31-apb0-gates

On Tue, Jun 17, 2014 at 10:52:41PM +0800, Chen-Yu Tsai wrote:
> sun6i-a31-apb0-gates supports using clock-indices for holes between
> individual gates. However, the driver passes the number of gates
> registered in clk_data->clk_num, which of_clk_src_onecell_get uses
> to recognize the range of valid indices a consumer can use.
>
> This patch makes the driver pass the maximum gate index + 1, so
> of_clk_src_onecell_get does not complain about indices greater
> than gates registered.
>
> This was tested on the A23 SoC, which has a similar APB0 clock,
> but has holes for gates to removed IP blocks.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (831.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 09:45:39

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 05/20] clk: sunxi: Support factor clocks with N multiplier factor starting from 1

On Tue, Jun 17, 2014 at 10:52:42PM +0800, Chen-Yu Tsai wrote:
> The PLLs on newer Allwinner SoC's, such as the A31 and A23, have a
> N multiplier factor that starts from 1, not 0.
>
> This patch adds an option to the clock driver's config data structures
> to define the difference.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> Acked-by: Maxime Ripard <[email protected]>
> ---
> drivers/clk/sunxi/clk-factors.c | 5 ++++-
> drivers/clk/sunxi/clk-factors.h | 1 +
> 2 files changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
> index 3806d97..399cf4d 100644
> --- a/drivers/clk/sunxi/clk-factors.c
> +++ b/drivers/clk/sunxi/clk-factors.c
> @@ -62,7 +62,10 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
> p = FACTOR_GET(config->pshift, config->pwidth, reg);
>
> /* Calculate the rate */
> - rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
> + if (config->n_from_one)
> + rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
> + else
> + rate = (parent_rate * n * (k + 1) >> p) / (m + 1);

Thinking a bit more about this, I wonder wether it wouldn't be better
to just have a n_start variable or something, and just use (n +
n_start) instead.

That would avoid having to declare twice the same function.

Maxime

>
> return rate;
> }
> diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
> index 02e1a43..0484a48 100644
> --- a/drivers/clk/sunxi/clk-factors.h
> +++ b/drivers/clk/sunxi/clk-factors.h
> @@ -15,6 +15,7 @@ struct clk_factors_config {
> u8 mwidth;
> u8 pshift;
> u8 pwidth;
> + u8 n_from_one;

Especially when you declare it as an u8, and not a bool.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (1.80 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 10:00:15

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 08/20] ARM: sun6i: DT: Rename PLL6 to PLL6x2 and add fixed-factor-clock for PLL6

On Tue, Jun 17, 2014 at 10:52:45PM +0800, Chen-Yu Tsai wrote:
> The PLL6 clock driver actually manages the PLL6x2 output of PLL6, so
> rename the node accordingly, and add a halved fixed-factor-clock for
> normal PLL6 output used by most modules.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> ---
> arch/arm/boot/dts/sun6i-a31.dtsi | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
> index a9dfa12..12d558b 100644
> --- a/arch/arm/boot/dts/sun6i-a31.dtsi
> +++ b/arch/arm/boot/dts/sun6i-a31.dtsi
> @@ -94,11 +94,20 @@
> clock-output-names = "pll1";
> };
>
> - pll6: clk@01c20028 {
> + pll6x2: clk@01c20028 {
> #clock-cells = <0>;
> compatible = "allwinner,sun6i-a31-pll6-clk";
> reg = <0x01c20028 0x4>;
> clocks = <&osc24M>;
> + clock-output-names = "pll6x2";
> + };
> +
> + pll6: pll6_clk {
> + #clock-cells = <0>;
> + compatible = "fixed-factor-clock";
> + clock-div = <2>;
> + clock-mult = <1>;
> + clocks = <&pll6x2>;
> clock-output-names = "pll6";
> };

Hmm, nope. The output of PLL6 is 24M * N * K / 2, and this is what we
support in the driver.

This change is backward, and should be the other way around. Have PLL6
running at it's usual speed, and then have PLL62X be a fixed-factor.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (1.43 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 10:05:47

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 09/20] clk: sunxi: Add sun6i MBUS clock support

On Tue, Jun 17, 2014 at 10:52:46PM +0800, Chen-Yu Tsai wrote:
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> ---
> Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
> drivers/clk/sunxi/clk-sunxi.c | 44 +++++++++++++++++++++++
> 2 files changed, 45 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index b9ec668..7b2ba41 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -40,6 +40,7 @@ Required properties:
> "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
> "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
> "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
> + "allwinner,sun6i-a31-mbus-clk" - for the MBUS clocks on A31 / A23
> "allwinner,sun7i-a20-out-clk" - for the external output clocks
> "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
> "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
> diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
> index eca3c6e..a086b5b 100644
> --- a/drivers/clk/sunxi/clk-sunxi.c
> +++ b/drivers/clk/sunxi/clk-sunxi.c
> @@ -307,6 +307,37 @@ static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate,
>
>
> /**
> + * sun6i_a31_get_mbus_factors() - calculates m factor for MBUS clocks
> + * MBUS rate is calculated as follows
> + * rate = parent_rate / (m + 1);
> + */
> +
> +static void sun6i_a31_get_mbus_factors(u32 *freq, u32 parent_rate,
> + u8 *n, u8 *k, u8 *m, u8 *p)
> +{
> + u8 div;
> +
> + /* These clocks can only divide, so we will never be able to achieve
> + * frequencies higher than the parent frequency */
> + if (*freq > parent_rate)
> + *freq = parent_rate;
> +
> + div = DIV_ROUND_UP(parent_rate, *freq);
> +
> + if (div > 8)
> + div = 8;
> +
> + *freq = parent_rate / div;
> +
> + /* we were called to round the frequency, we can now return */
> + if (n == NULL)

s/n/m/ ?

> + return;
> +
> + *m = div - 1;
> +}
> +
> +
> +/**
> * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B
> * CLK_OUT rate is calculated as follows
> * rate = (parent_rate >> p) / (m + 1);
> @@ -447,6 +478,11 @@ static struct clk_factors_config sun4i_mod0_config = {
> .pwidth = 2,
> };
>
> +static struct clk_factors_config sun6i_a31_mbus_config = {
> + .mshift = 0,
> + .mwidth = 3,

Actually, the A31 has an extra N factor.

So this mbus clock looks like it's only about the A23, and not the A31
at all.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (2.67 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 10:10:19

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 10/20] clk: sunxi: Add support for table-based divider clocks

On Tue, Jun 17, 2014 at 10:52:47PM +0800, Chen-Yu Tsai wrote:
> A few of the clock modules have odd dividers, such as
> the 2 lowest dividers being the same (2), or have the
> same divider when the highest bit is set.
>
> This patch adds support for optional divider tables,
> so the clock framework will know about the odd values.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (558.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 10:20:36

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 11/20] clk: sunxi: Add A23 clocks support

On Tue, Jun 17, 2014 at 10:52:48PM +0800, Chen-Yu Tsai wrote:
> The clock control unit on the A23 is similar to the one found on the A31.
>
> The AHB1, APB1, APB2 gates on the A23 are almost identical to the ones
> on the A31, but some outputs are missing.
>
> The main CPU PLL (PLL1) however is like that on older Allwinner SoCs, such
> as the A10 or A20, but the N factor starts from 1 instead of 0.
>
> This patch adds support for PLL1 and all the basic clock gates.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Except for the minor comment below, you have my

Acked-by: Maxime Ripard <[email protected]>

> ---
> Documentation/devicetree/bindings/clock/sunxi.txt | 5 +
> drivers/clk/sunxi/clk-sunxi.c | 115 ++++++++++++++++++++++
> 2 files changed, 120 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index 7b2ba41..af9e47d 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -9,11 +9,13 @@ Required properties:
> "allwinner,sun4i-a10-osc-clk" - for a gatable oscillator
> "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
> "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
> + "allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23
> "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
> "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
> "allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
> "allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
> "allwinner,sun4i-a10-axi-clk" - for the AXI clock
> + "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23
> "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
> "allwinner,sun4i-a10-ahb-clk" - for the AHB clock
> "allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10
> @@ -23,6 +25,7 @@ Required properties:
> "allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
> "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
> "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
> + "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
> "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
> "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
> "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
> @@ -37,8 +40,10 @@ Required properties:
> "allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
> "allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
> "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
> + "allwinner,sun8i-a23-apb1-gates-clk" - for the APB1 gates on A23
> "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
> "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
> + "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
> "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
> "allwinner,sun6i-a31-mbus-clk" - for the MBUS clocks on A31 / A23
> "allwinner,sun7i-a20-out-clk" - for the external output clocks
> diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
> index 7e2f015..f418392 100644
> --- a/drivers/clk/sunxi/clk-sunxi.c
> +++ b/drivers/clk/sunxi/clk-sunxi.c
> @@ -164,6 +164,54 @@ static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate,
> }
>
> /**
> + * sun8i_a23_get_pll1_factors() - calculates n, k, m, p factors for PLL1
> + * PLL1 rate is calculated as follows
> + * rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
> + * parent_rate is always 24Mhz
> + */
> +
> +static void sun8i_a23_get_pll1_factors(u32 *freq, u32 parent_rate,
> + u8 *n, u8 *k, u8 *m, u8 *p)
> +{
> + u8 div;
> +
> + /* Normalize value to a 6M multiple */
> + div = *freq / 6000000;
> + *freq = 6000000 * div;
> +
> + /* we were called to round the frequency, we can now return */
> + if (n == NULL)
> + return;
> +
> + /* m is always zero for pll1 */
> + *m = 0;
> +
> + /* k is 1 only on these cases */
> + if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000)
> + *k = 1;
> + else
> + *k = 0;
> +
> + /* p will be 2 for divs under 20 and odd divs under 32 */
> + if (div < 20 || (div < 32 && (div & 1)))
> + *p = 2;
> +
> + /* p will be 1 for even divs under 32, divs under 40 and odd pairs
> + * of divs between 40-62 */
> + else if (div < 40 || (div < 64 && (div & 2)))
> + *p = 1;
> +
> + /* any other entries have p = 0 */
> + else
> + *p = 0;
> +
> + /* calculate a suitable n based on k and p */
> + div <<= *p;
> + div /= (*k + 1);
> + *n = div / 4 - 1;
> +}
> +
> +/**
> * sun4i_get_pll5_factors() - calculates n, k factors for PLL5
> * PLL5 rate is calculated as follows
> * rate = parent_rate * n * (k + 1)
> @@ -448,6 +496,18 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
> .n_from_one = 1,
> };
>
> +static struct clk_factors_config sun8i_a23_pll1_config = {
> + .nshift = 8,
> + .nwidth = 5,
> + .kshift = 4,
> + .kwidth = 2,
> + .mshift = 0,
> + .mwidth = 2,
> + .pshift = 16,
> + .pwidth = 2,
> + .n_from_one = 1,
> +};
> +
> static struct clk_factors_config sun4i_pll5_config = {
> .nshift = 8,
> .nwidth = 5,
> @@ -503,6 +563,12 @@ static const struct factors_data sun6i_a31_pll1_data __initconst = {
> .getter = sun6i_a31_get_pll1_factors,
> };
>
> +static const struct factors_data sun8i_a23_pll1_data __initconst = {
> + .enable = 31,
> + .table = &sun8i_a23_pll1_config,
> + .getter = sun8i_a23_get_pll1_factors,
> +};
> +
> static const struct factors_data sun7i_a20_pll4_data __initconst = {
> .enable = 31,
> .table = &sun4i_pll5_config,
> @@ -712,6 +778,25 @@ static const struct div_data sun4i_axi_data __initconst = {
> .width = 2,
> };
>
> +static const struct clk_div_table sun8i_a23_axi_table[] __initconst = {
> + { .val = 0, .div = 1 },
> + { .val = 1, .div = 2 },
> + { .val = 2, .div = 3 },
> + { .val = 3, .div = 4 },
> + { .val = 4, .div = 4 },
> + { .val = 5, .div = 4 },
> + { .val = 6, .div = 4 },
> + { .val = 7, .div = 4 },
> + { } /* sentinel */
> +};
> +
> +static const struct div_data sun8i_a23_axi_data __initconst = {
> + .shift = 0,
> + .pow = 0,
> + .width = 8,
> + .table = sun8i_a23_axi_table,
> +};
> +
> static const struct div_data sun4i_ahb_data __initconst = {
> .shift = 4,
> .pow = 1,
> @@ -844,6 +929,10 @@ static const struct gates_data sun7i_a20_ahb_gates_data __initconst = {
> .mask = { 0x12f77fff, 0x16ff3f },
> };
>
> +static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = {
> + .mask = {0x25386742, 0x2505111},
> +};
> +
> static const struct gates_data sun4i_apb0_gates_data __initconst = {
> .mask = {0x4EF},
> };
> @@ -876,6 +965,10 @@ static const struct gates_data sun6i_a31_apb1_gates_data __initconst = {
> .mask = {0x3031},
> };
>
> +static const struct gates_data sun8i_a23_apb1_gates_data __initconst = {
> + .mask = {0x3021},
> +};
> +
> static const struct gates_data sun6i_a31_apb2_gates_data __initconst = {
> .mask = {0x3F000F},
> };
> @@ -884,6 +977,10 @@ static const struct gates_data sun7i_a20_apb1_gates_data __initconst = {
> .mask = { 0xff80ff },
> };
>
> +static const struct gates_data sun8i_a23_apb2_gates_data __initconst = {
> + .mask = {0x1F0007},
> +};
> +
> static const struct gates_data sun4i_a10_usb_gates_data __initconst = {
> .mask = {0x1C0},
> .reset_mask = 0x07,
> @@ -1139,6 +1236,7 @@ free_clkdata:
> static const struct of_device_id clk_factors_match[] __initconst = {
> {.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,},
> {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
> + {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,},
> {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,},
> {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
> {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
> @@ -1151,6 +1249,7 @@ static const struct of_device_id clk_factors_match[] __initconst = {
> /* Matches for divider clocks */
> static const struct of_device_id clk_div_match[] __initconst = {
> {.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,},
> + {.compatible = "allwinner,sun8i-a23-axi-clk", .data = &sun8i_a23_axi_data,},
> {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,},
> {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,},
> {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
> @@ -1180,6 +1279,7 @@ static const struct of_device_id clk_gates_match[] __initconst = {
> {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
> {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
> {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
> + {.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,},
> {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
> {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
> {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
> @@ -1189,7 +1289,9 @@ static const struct of_device_id clk_gates_match[] __initconst = {
> {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
> {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
> {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
> + {.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,},
> {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
> + {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,},
> {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
> {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,},
> {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,},
> @@ -1276,3 +1378,16 @@ static void __init sun6i_init_clocks(struct device_node *node)
> ARRAY_SIZE(sun6i_critical_clocks));
> }
> CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
> +
> +static const char *sun8i_critical_clocks[] __initdata = {
> + "cpu",
> + "ahb1_sdram",
> + "mbus",
> +};
> +
> +static void __init sun8i_init_clocks(void)

This has the wrong prototype and will trigger a warning.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (10.65 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 10:20:42

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 13/20] clk: sunxi: Add A23 specific compatible to sun6i-a31-apb0-gates-clk

On Tue, Jun 17, 2014 at 10:52:50PM +0800, Chen-Yu Tsai wrote:
> The sun6i-a31-apb0-gates-clk driver is generic in that it supports
> the "clock-indicies" DT property with "clock-output-names" to list
> the valid clock gate bits.
>
> However this might lead one to assume that the clock in the A23 is
> the same as the A31. To make it clear, we add a new compatible for
> the A23, "allwinner,sun8i-a23-apb0-gates-clk".
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (644.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 10:30:06

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 12/20] clk: sunxi: Add A23 APB0 support to sun6i-a31-apb0-clk

On Tue, Jun 17, 2014 at 10:52:49PM +0800, Chen-Yu Tsai wrote:
> The A23 has an almost identical PRCM clock tree. The difference in
> the APB0 clock is the smallest divisor is 1, instead of 2.
>
> This patch extends the sun6i-a31-apb0-clk driver to take divider
> tables associated to compatibles, and adds a compatible for the A23
> variant.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> ---
> Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
> drivers/clk/sunxi/clk-sun6i-apb0.c | 28 ++++++++++++++++++-----
> 2 files changed, 23 insertions(+), 6 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index af9e47d..e3a47ec 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -28,6 +28,7 @@ Required properties:
> "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
> "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
> "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
> + "allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23
> "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
> "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
> "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
> diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c
> index 11f17c3..2197ac7 100644
> --- a/drivers/clk/sunxi/clk-sun6i-apb0.c
> +++ b/drivers/clk/sunxi/clk-sun6i-apb0.c
> @@ -11,6 +11,7 @@
> #include <linux/clk-provider.h>
> #include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/of_device.h>
> #include <linux/platform_device.h>
>
> /*
> @@ -28,6 +29,21 @@ static const struct clk_div_table sun6i_a31_apb0_divs[] = {
> { /* sentinel */ },
> };
>
> +/* The A23 APB0 clock has a standard power of 2 divisor */

Why not just pass CLK_DIVIDER_POWER_OF_TWO then, instead of a table?

> +static const struct clk_div_table sun8i_a23_apb0_divs[] = {
> + { .val = 0, .div = 1, },
> + { .val = 1, .div = 2, },
> + { .val = 2, .div = 4, },
> + { .val = 3, .div = 8, },
> + { /* sentinel */ },
> +};
> +
> +const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = {
> + { .compatible = "allwinner,sun6i-a31-apb0-clk", .data = &sun6i_a31_apb0_divs },
> + { .compatible = "allwinner,sun8i-a23-apb0-clk", .data = &sun8i_a23_apb0_divs },
> + { /* sentinel */ }
> +};
> +
> static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
> {
> struct device_node *np = pdev->dev.of_node;
> @@ -36,12 +52,17 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
> struct resource *r;
> void __iomem *reg;
> struct clk *clk;
> + const struct of_device_id *device;
>
> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> reg = devm_ioremap_resource(&pdev->dev, r);
> if (IS_ERR(reg))
> return PTR_ERR(reg);
>
> + device = of_match_device(sun6i_a31_apb0_clk_dt_ids, &pdev->dev);
> + if (!device)
> + return -EINVAL;
> +
> clk_parent = of_clk_get_parent_name(np, 0);
> if (!clk_parent)
> return -EINVAL;
> @@ -49,7 +70,7 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
> of_property_read_string(np, "clock-output-names", &clk_name);
>
> clk = clk_register_divider_table(&pdev->dev, clk_name, clk_parent,
> - 0, reg, 0, 2, 0, sun6i_a31_apb0_divs,
> + 0, reg, 0, 2, 0, device->data,

I'm not sure that it will actually work for the A31, since it does
define some dividers anyway, and the divider table is !NULL, even
though there's actually no dividers defined.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (3.68 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 12:25:08

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 16/20] mfd: sun6i-prcm: Add support for Allwinner A23 PRCM

On Wed, Jun 18, 2014 at 09:29:53AM +0100, Lee Jones wrote:
> > The Allwinner A23 SoC has a PRCM unit like the previous A31 SoC.
> > The differences are the AR100 clock can no longer be modified,
> > the APB0 clock has different divisors, and some clock gates are
> > gone.
> >
> > This patch adds a compatible with a modified subdevice list for
> > the A23.
> >
> > Signed-off-by: Chen-Yu Tsai <[email protected]>
> > ---
> > .../devicetree/bindings/mfd/sun6i-prcm.txt | 2 +-
> > drivers/mfd/sun6i-prcm.c | 30 ++++++++++++++++++++++
> > 2 files changed, 31 insertions(+), 1 deletion(-)
>
> The patch looks fine to me, but I'm concerned about the size of the
> patch set and the amount of subsystems it touches.
>
> I am guessing that this patch can just be taken independently though.
> Please correct me if I'm wrong.

I have a bit of the same concern. We have several comments on the
previous patches, so I'm not even sure this patch can go as is.

It would be much easier if you (ChenYu) could introduce first a very
basic with just the UART support, and then, as separate series,
clocks, PRCM, MMC, and so on.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (1.24 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 12:30:10

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 18/20] ARM: sunxi: Add earlyprintk support using R_UART (sun6i/sun8i)

On Tue, Jun 17, 2014 at 10:52:55PM +0800, Chen-Yu Tsai wrote:
> sun6i/sun8i have a UART in the RTC block group, which can be used
> as an early console. This is most useful on sun8i as UART0 is muxed
> with MMC0, which is not available if we boot from MMC.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (482.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-18 12:30:08

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 17/20] ARM: sunxi: Introduce Allwinner A23 support

On Tue, Jun 17, 2014 at 10:52:54PM +0800, Chen-Yu Tsai wrote:
> The Allwinner A23 is a dual-core Cortex-A7-based SoC. It re-uses most of
> the IPs found in previous SoCs, notably the A31.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> ---
> arch/arm/mach-sunxi/Kconfig | 8 ++++++++
> arch/arm/mach-sunxi/sunxi.c | 10 ++++++++++
> 2 files changed, 18 insertions(+)
>
> diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
> index 0fbd4f1..6434e3b 100644
> --- a/arch/arm/mach-sunxi/Kconfig
> +++ b/arch/arm/mach-sunxi/Kconfig
> @@ -35,4 +35,12 @@ config MACH_SUN7I
> select HAVE_ARM_ARCH_TIMER
> select SUN5I_HSTIMER
>
> +config MACH_SUN8I
> + bool "Allwinner A23 (sun8i) SoCs support"
> + default ARCH_SUNXI
> + select ARCH_HAS_RESET_CONTROLLER
> + select ARM_GIC
> + select MFD_SUN6I_PRCM
> + select RESET_CONTROLLER
> +
> endif
> diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
> index 3f9587b..962ff30 100644
> --- a/arch/arm/mach-sunxi/sunxi.c
> +++ b/arch/arm/mach-sunxi/sunxi.c
> @@ -53,3 +53,13 @@ static const char * const sun7i_board_dt_compat[] = {
> DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family")
> .dt_compat = sun7i_board_dt_compat,
> MACHINE_END
> +
> +static const char * const sun8i_board_dt_compat[] = {
> + "allwinner,sun8i-a23",
> + NULL,
> +};
> +
> +DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family")
> + .init_time = sun6i_timer_init,

I haven't seen anything in your code that needed to use this
function. Am I missing something?

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (1.61 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-19 04:08:14

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH v2 11/20] clk: sunxi: Add A23 clocks support

On Wed, Jun 18, 2014 at 6:16 PM, Maxime Ripard
<[email protected]> wrote:
> On Tue, Jun 17, 2014 at 10:52:48PM +0800, Chen-Yu Tsai wrote:
>> The clock control unit on the A23 is similar to the one found on the A31.
>>
>> The AHB1, APB1, APB2 gates on the A23 are almost identical to the ones
>> on the A31, but some outputs are missing.
>>
>> The main CPU PLL (PLL1) however is like that on older Allwinner SoCs, such
>> as the A10 or A20, but the N factor starts from 1 instead of 0.
>>
>> This patch adds support for PLL1 and all the basic clock gates.
>>
>> Signed-off-by: Chen-Yu Tsai <[email protected]>
>
> Except for the minor comment below, you have my
>
> Acked-by: Maxime Ripard <[email protected]>
>
>> ---
>> Documentation/devicetree/bindings/clock/sunxi.txt | 5 +
>> drivers/clk/sunxi/clk-sunxi.c | 115 ++++++++++++++++++++++
>> 2 files changed, 120 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
>> index 7b2ba41..af9e47d 100644
>> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
>> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
>> @@ -9,11 +9,13 @@ Required properties:
>> "allwinner,sun4i-a10-osc-clk" - for a gatable oscillator
>> "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
>> "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
>> + "allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23
>> "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
>> "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
>> "allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
>> "allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
>> "allwinner,sun4i-a10-axi-clk" - for the AXI clock
>> + "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23
>> "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
>> "allwinner,sun4i-a10-ahb-clk" - for the AHB clock
>> "allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10
>> @@ -23,6 +25,7 @@ Required properties:
>> "allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
>> "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
>> "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
>> + "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
>> "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
>> "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
>> "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
>> @@ -37,8 +40,10 @@ Required properties:
>> "allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
>> "allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
>> "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
>> + "allwinner,sun8i-a23-apb1-gates-clk" - for the APB1 gates on A23
>> "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
>> "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
>> + "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
>> "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
>> "allwinner,sun6i-a31-mbus-clk" - for the MBUS clocks on A31 / A23
>> "allwinner,sun7i-a20-out-clk" - for the external output clocks
>> diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
>> index 7e2f015..f418392 100644
>> --- a/drivers/clk/sunxi/clk-sunxi.c
>> +++ b/drivers/clk/sunxi/clk-sunxi.c
>> @@ -164,6 +164,54 @@ static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate,
>> }
>>
>> /**
>> + * sun8i_a23_get_pll1_factors() - calculates n, k, m, p factors for PLL1
>> + * PLL1 rate is calculated as follows
>> + * rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
>> + * parent_rate is always 24Mhz
>> + */
>> +
>> +static void sun8i_a23_get_pll1_factors(u32 *freq, u32 parent_rate,
>> + u8 *n, u8 *k, u8 *m, u8 *p)
>> +{
>> + u8 div;
>> +
>> + /* Normalize value to a 6M multiple */
>> + div = *freq / 6000000;
>> + *freq = 6000000 * div;
>> +
>> + /* we were called to round the frequency, we can now return */
>> + if (n == NULL)
>> + return;
>> +
>> + /* m is always zero for pll1 */
>> + *m = 0;
>> +
>> + /* k is 1 only on these cases */
>> + if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000)
>> + *k = 1;
>> + else
>> + *k = 0;
>> +
>> + /* p will be 2 for divs under 20 and odd divs under 32 */
>> + if (div < 20 || (div < 32 && (div & 1)))
>> + *p = 2;
>> +
>> + /* p will be 1 for even divs under 32, divs under 40 and odd pairs
>> + * of divs between 40-62 */
>> + else if (div < 40 || (div < 64 && (div & 2)))
>> + *p = 1;
>> +
>> + /* any other entries have p = 0 */
>> + else
>> + *p = 0;
>> +
>> + /* calculate a suitable n based on k and p */
>> + div <<= *p;
>> + div /= (*k + 1);
>> + *n = div / 4 - 1;
>> +}
>> +
>> +/**
>> * sun4i_get_pll5_factors() - calculates n, k factors for PLL5
>> * PLL5 rate is calculated as follows
>> * rate = parent_rate * n * (k + 1)
>> @@ -448,6 +496,18 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
>> .n_from_one = 1,
>> };
>>
>> +static struct clk_factors_config sun8i_a23_pll1_config = {
>> + .nshift = 8,
>> + .nwidth = 5,
>> + .kshift = 4,
>> + .kwidth = 2,
>> + .mshift = 0,
>> + .mwidth = 2,
>> + .pshift = 16,
>> + .pwidth = 2,
>> + .n_from_one = 1,
>> +};
>> +
>> static struct clk_factors_config sun4i_pll5_config = {
>> .nshift = 8,
>> .nwidth = 5,
>> @@ -503,6 +563,12 @@ static const struct factors_data sun6i_a31_pll1_data __initconst = {
>> .getter = sun6i_a31_get_pll1_factors,
>> };
>>
>> +static const struct factors_data sun8i_a23_pll1_data __initconst = {
>> + .enable = 31,
>> + .table = &sun8i_a23_pll1_config,
>> + .getter = sun8i_a23_get_pll1_factors,
>> +};
>> +
>> static const struct factors_data sun7i_a20_pll4_data __initconst = {
>> .enable = 31,
>> .table = &sun4i_pll5_config,
>> @@ -712,6 +778,25 @@ static const struct div_data sun4i_axi_data __initconst = {
>> .width = 2,
>> };
>>
>> +static const struct clk_div_table sun8i_a23_axi_table[] __initconst = {
>> + { .val = 0, .div = 1 },
>> + { .val = 1, .div = 2 },
>> + { .val = 2, .div = 3 },
>> + { .val = 3, .div = 4 },
>> + { .val = 4, .div = 4 },
>> + { .val = 5, .div = 4 },
>> + { .val = 6, .div = 4 },
>> + { .val = 7, .div = 4 },
>> + { } /* sentinel */
>> +};
>> +
>> +static const struct div_data sun8i_a23_axi_data __initconst = {
>> + .shift = 0,
>> + .pow = 0,
>> + .width = 8,
>> + .table = sun8i_a23_axi_table,
>> +};
>> +
>> static const struct div_data sun4i_ahb_data __initconst = {
>> .shift = 4,
>> .pow = 1,
>> @@ -844,6 +929,10 @@ static const struct gates_data sun7i_a20_ahb_gates_data __initconst = {
>> .mask = { 0x12f77fff, 0x16ff3f },
>> };
>>
>> +static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = {
>> + .mask = {0x25386742, 0x2505111},
>> +};
>> +
>> static const struct gates_data sun4i_apb0_gates_data __initconst = {
>> .mask = {0x4EF},
>> };
>> @@ -876,6 +965,10 @@ static const struct gates_data sun6i_a31_apb1_gates_data __initconst = {
>> .mask = {0x3031},
>> };
>>
>> +static const struct gates_data sun8i_a23_apb1_gates_data __initconst = {
>> + .mask = {0x3021},
>> +};
>> +
>> static const struct gates_data sun6i_a31_apb2_gates_data __initconst = {
>> .mask = {0x3F000F},
>> };
>> @@ -884,6 +977,10 @@ static const struct gates_data sun7i_a20_apb1_gates_data __initconst = {
>> .mask = { 0xff80ff },
>> };
>>
>> +static const struct gates_data sun8i_a23_apb2_gates_data __initconst = {
>> + .mask = {0x1F0007},
>> +};
>> +
>> static const struct gates_data sun4i_a10_usb_gates_data __initconst = {
>> .mask = {0x1C0},
>> .reset_mask = 0x07,
>> @@ -1139,6 +1236,7 @@ free_clkdata:
>> static const struct of_device_id clk_factors_match[] __initconst = {
>> {.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,},
>> {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
>> + {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,},
>> {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,},
>> {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
>> {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
>> @@ -1151,6 +1249,7 @@ static const struct of_device_id clk_factors_match[] __initconst = {
>> /* Matches for divider clocks */
>> static const struct of_device_id clk_div_match[] __initconst = {
>> {.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,},
>> + {.compatible = "allwinner,sun8i-a23-axi-clk", .data = &sun8i_a23_axi_data,},
>> {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,},
>> {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,},
>> {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
>> @@ -1180,6 +1279,7 @@ static const struct of_device_id clk_gates_match[] __initconst = {
>> {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
>> {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
>> {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
>> + {.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,},
>> {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
>> {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
>> {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
>> @@ -1189,7 +1289,9 @@ static const struct of_device_id clk_gates_match[] __initconst = {
>> {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
>> {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
>> {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
>> + {.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,},
>> {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
>> + {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,},
>> {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
>> {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,},
>> {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,},
>> @@ -1276,3 +1378,16 @@ static void __init sun6i_init_clocks(struct device_node *node)
>> ARRAY_SIZE(sun6i_critical_clocks));
>> }
>> CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
>> +
>> +static const char *sun8i_critical_clocks[] __initdata = {
>> + "cpu",
>> + "ahb1_sdram",
>> + "mbus",
>> +};
>> +
>> +static void __init sun8i_init_clocks(void)
>
> This has the wrong prototype and will trigger a warning.

Ah, this was fixed during the latest cycle. Thanks.

2014-06-19 04:34:05

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH v2 12/20] clk: sunxi: Add A23 APB0 support to sun6i-a31-apb0-clk

On Wed, Jun 18, 2014 at 6:26 PM, Maxime Ripard
<[email protected]> wrote:
> On Tue, Jun 17, 2014 at 10:52:49PM +0800, Chen-Yu Tsai wrote:
>> The A23 has an almost identical PRCM clock tree. The difference in
>> the APB0 clock is the smallest divisor is 1, instead of 2.
>>
>> This patch extends the sun6i-a31-apb0-clk driver to take divider
>> tables associated to compatibles, and adds a compatible for the A23
>> variant.
>>
>> Signed-off-by: Chen-Yu Tsai <[email protected]>
>> ---
>> Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
>> drivers/clk/sunxi/clk-sun6i-apb0.c | 28 ++++++++++++++++++-----
>> 2 files changed, 23 insertions(+), 6 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
>> index af9e47d..e3a47ec 100644
>> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
>> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
>> @@ -28,6 +28,7 @@ Required properties:
>> "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
>> "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
>> "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
>> + "allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23
>> "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
>> "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
>> "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
>> diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c
>> index 11f17c3..2197ac7 100644
>> --- a/drivers/clk/sunxi/clk-sun6i-apb0.c
>> +++ b/drivers/clk/sunxi/clk-sun6i-apb0.c
>> @@ -11,6 +11,7 @@
>> #include <linux/clk-provider.h>
>> #include <linux/module.h>
>> #include <linux/of.h>
>> +#include <linux/of_device.h>
>> #include <linux/platform_device.h>
>>
>> /*
>> @@ -28,6 +29,21 @@ static const struct clk_div_table sun6i_a31_apb0_divs[] = {

For reference:

static const struct clk_div_table sun6i_a31_apb0_divs[] = {
{ .val = 0, .div = 2, },
{ .val = 1, .div = 2, },
{ .val = 2, .div = 4, },
{ .val = 3, .div = 8, },
{ /* sentinel */ },
};


>> { /* sentinel */ },
>> };
>>
>> +/* The A23 APB0 clock has a standard power of 2 divisor */
>
> Why not just pass CLK_DIVIDER_POWER_OF_TWO then, instead of a table?

The A31 APB0 clock uses a table for the odd /2 divisor for value 0.
The standard table I'm using for the A23 is just to keep it simple
and alike.

>> +static const struct clk_div_table sun8i_a23_apb0_divs[] = {
>> + { .val = 0, .div = 1, },
>> + { .val = 1, .div = 2, },
>> + { .val = 2, .div = 4, },
>> + { .val = 3, .div = 8, },
>> + { /* sentinel */ },
>> +};
>> +
>> +const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = {
>> + { .compatible = "allwinner,sun6i-a31-apb0-clk", .data = &sun6i_a31_apb0_divs },
>> + { .compatible = "allwinner,sun8i-a23-apb0-clk", .data = &sun8i_a23_apb0_divs },
>> + { /* sentinel */ }
>> +};
>> +
>> static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
>> {
>> struct device_node *np = pdev->dev.of_node;
>> @@ -36,12 +52,17 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
>> struct resource *r;
>> void __iomem *reg;
>> struct clk *clk;
>> + const struct of_device_id *device;
>>
>> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> reg = devm_ioremap_resource(&pdev->dev, r);
>> if (IS_ERR(reg))
>> return PTR_ERR(reg);
>>
>> + device = of_match_device(sun6i_a31_apb0_clk_dt_ids, &pdev->dev);
>> + if (!device)
>> + return -EINVAL;
>> +
>> clk_parent = of_clk_get_parent_name(np, 0);
>> if (!clk_parent)
>> return -EINVAL;
>> @@ -49,7 +70,7 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
>> of_property_read_string(np, "clock-output-names", &clk_name);
>>
>> clk = clk_register_divider_table(&pdev->dev, clk_name, clk_parent,
>> - 0, reg, 0, 2, 0, sun6i_a31_apb0_divs,
>> + 0, reg, 0, 2, 0, device->data,
>
> I'm not sure that it will actually work for the A31, since it does
> define some dividers anyway, and the divider table is !NULL, even
> though there's actually no dividers defined.

I'm not following. The A31 does have a table defined. It's just cut
off in this patch. I asked Boris to add the table when he was working
on the A31 PRCM clocks. See above.


Cheers
ChenYu

2014-06-19 09:30:08

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 12/20] clk: sunxi: Add A23 APB0 support to sun6i-a31-apb0-clk

On Thu, Jun 19, 2014 at 12:33:41PM +0800, Chen-Yu Tsai wrote:
> On Wed, Jun 18, 2014 at 6:26 PM, Maxime Ripard
> <[email protected]> wrote:
> > On Tue, Jun 17, 2014 at 10:52:49PM +0800, Chen-Yu Tsai wrote:
> >> The A23 has an almost identical PRCM clock tree. The difference in
> >> the APB0 clock is the smallest divisor is 1, instead of 2.
> >>
> >> This patch extends the sun6i-a31-apb0-clk driver to take divider
> >> tables associated to compatibles, and adds a compatible for the A23
> >> variant.
> >>
> >> Signed-off-by: Chen-Yu Tsai <[email protected]>
> >> ---
> >> Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
> >> drivers/clk/sunxi/clk-sun6i-apb0.c | 28 ++++++++++++++++++-----
> >> 2 files changed, 23 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> >> index af9e47d..e3a47ec 100644
> >> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> >> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> >> @@ -28,6 +28,7 @@ Required properties:
> >> "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
> >> "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
> >> "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
> >> + "allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23
> >> "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
> >> "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
> >> "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
> >> diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c
> >> index 11f17c3..2197ac7 100644
> >> --- a/drivers/clk/sunxi/clk-sun6i-apb0.c
> >> +++ b/drivers/clk/sunxi/clk-sun6i-apb0.c
> >> @@ -11,6 +11,7 @@
> >> #include <linux/clk-provider.h>
> >> #include <linux/module.h>
> >> #include <linux/of.h>
> >> +#include <linux/of_device.h>
> >> #include <linux/platform_device.h>
> >>
> >> /*
> >> @@ -28,6 +29,21 @@ static const struct clk_div_table sun6i_a31_apb0_divs[] = {
>
> For reference:
>
> static const struct clk_div_table sun6i_a31_apb0_divs[] = {
> { .val = 0, .div = 2, },
> { .val = 1, .div = 2, },
> { .val = 2, .div = 4, },
> { .val = 3, .div = 8, },
> { /* sentinel */ },
> };
>
>
> >> { /* sentinel */ },
> >> };
> >>
> >> +/* The A23 APB0 clock has a standard power of 2 divisor */
> >
> > Why not just pass CLK_DIVIDER_POWER_OF_TWO then, instead of a table?
>
> The A31 APB0 clock uses a table for the odd /2 divisor for value 0.
> The standard table I'm using for the A23 is just to keep it simple
> and alike.
>
> >> +static const struct clk_div_table sun8i_a23_apb0_divs[] = {
> >> + { .val = 0, .div = 1, },
> >> + { .val = 1, .div = 2, },
> >> + { .val = 2, .div = 4, },
> >> + { .val = 3, .div = 8, },
> >> + { /* sentinel */ },
> >> +};
> >> +
> >> +const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = {
> >> + { .compatible = "allwinner,sun6i-a31-apb0-clk", .data = &sun6i_a31_apb0_divs },
> >> + { .compatible = "allwinner,sun8i-a23-apb0-clk", .data = &sun8i_a23_apb0_divs },
> >> + { /* sentinel */ }
> >> +};
> >> +
> >> static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
> >> {
> >> struct device_node *np = pdev->dev.of_node;
> >> @@ -36,12 +52,17 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
> >> struct resource *r;
> >> void __iomem *reg;
> >> struct clk *clk;
> >> + const struct of_device_id *device;
> >>
> >> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> reg = devm_ioremap_resource(&pdev->dev, r);
> >> if (IS_ERR(reg))
> >> return PTR_ERR(reg);
> >>
> >> + device = of_match_device(sun6i_a31_apb0_clk_dt_ids, &pdev->dev);
> >> + if (!device)
> >> + return -EINVAL;
> >> +
> >> clk_parent = of_clk_get_parent_name(np, 0);
> >> if (!clk_parent)
> >> return -EINVAL;
> >> @@ -49,7 +70,7 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
> >> of_property_read_string(np, "clock-output-names", &clk_name);
> >>
> >> clk = clk_register_divider_table(&pdev->dev, clk_name, clk_parent,
> >> - 0, reg, 0, 2, 0, sun6i_a31_apb0_divs,
> >> + 0, reg, 0, 2, 0, device->data,
> >
> > I'm not sure that it will actually work for the A31, since it does
> > define some dividers anyway, and the divider table is !NULL, even
> > though there's actually no dividers defined.
>
> I'm not following. The A31 does have a table defined. It's just cut
> off in this patch. I asked Boris to add the table when he was working
> on the A31 PRCM clocks. See above.

Ah right. My bad.

If these two clocks are these different though, maybe it would just be
easier to add a new driver. These are trivial enough anyway.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (5.04 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-06-20 05:57:19

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH v2 17/20] ARM: sunxi: Introduce Allwinner A23 support

On Wed, Jun 18, 2014 at 8:26 PM, Maxime Ripard
<[email protected]> wrote:
> On Tue, Jun 17, 2014 at 10:52:54PM +0800, Chen-Yu Tsai wrote:
>> The Allwinner A23 is a dual-core Cortex-A7-based SoC. It re-uses most of
>> the IPs found in previous SoCs, notably the A31.
>>
>> Signed-off-by: Chen-Yu Tsai <[email protected]>
>> ---
>> arch/arm/mach-sunxi/Kconfig | 8 ++++++++
>> arch/arm/mach-sunxi/sunxi.c | 10 ++++++++++
>> 2 files changed, 18 insertions(+)
>>
>> diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
>> index 0fbd4f1..6434e3b 100644
>> --- a/arch/arm/mach-sunxi/Kconfig
>> +++ b/arch/arm/mach-sunxi/Kconfig
>> @@ -35,4 +35,12 @@ config MACH_SUN7I
>> select HAVE_ARM_ARCH_TIMER
>> select SUN5I_HSTIMER
>>
>> +config MACH_SUN8I
>> + bool "Allwinner A23 (sun8i) SoCs support"
>> + default ARCH_SUNXI
>> + select ARCH_HAS_RESET_CONTROLLER
>> + select ARM_GIC
>> + select MFD_SUN6I_PRCM
>> + select RESET_CONTROLLER
>> +
>> endif
>> diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
>> index 3f9587b..962ff30 100644
>> --- a/arch/arm/mach-sunxi/sunxi.c
>> +++ b/arch/arm/mach-sunxi/sunxi.c
>> @@ -53,3 +53,13 @@ static const char * const sun7i_board_dt_compat[] = {
>> DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family")
>> .dt_compat = sun7i_board_dt_compat,
>> MACHINE_END
>> +
>> +static const char * const sun8i_board_dt_compat[] = {
>> + "allwinner,sun8i-a23",
>> + NULL,
>> +};
>> +
>> +DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family")
>> + .init_time = sun6i_timer_init,
>
> I haven't seen anything in your code that needed to use this
> function. Am I missing something?

My mistake. From the log I thought all timers needed the reset
controller. Turns out only the high speed timer does.

I'll remove the call in the next version.


ChenYu

2014-06-20 05:59:31

by Chen-Yu Tsai

[permalink] [raw]
Subject: Fwd: [linux-sunxi] Re: [PATCH v2 17/20] ARM: sunxi: Introduce Allwinner A23 support

On Wed, Jun 18, 2014 at 8:26 PM, Maxime Ripard
<[email protected]> wrote:
> On Tue, Jun 17, 2014 at 10:52:54PM +0800, Chen-Yu Tsai wrote:
>> The Allwinner A23 is a dual-core Cortex-A7-based SoC. It re-uses most of
>> the IPs found in previous SoCs, notably the A31.
>>
>> Signed-off-by: Chen-Yu Tsai <[email protected]>
>> ---
>> arch/arm/mach-sunxi/Kconfig | 8 ++++++++
>> arch/arm/mach-sunxi/sunxi.c | 10 ++++++++++
>> 2 files changed, 18 insertions(+)
>>
>> diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
>> index 0fbd4f1..6434e3b 100644
>> --- a/arch/arm/mach-sunxi/Kconfig
>> +++ b/arch/arm/mach-sunxi/Kconfig
>> @@ -35,4 +35,12 @@ config MACH_SUN7I
>> select HAVE_ARM_ARCH_TIMER
>> select SUN5I_HSTIMER
>>
>> +config MACH_SUN8I
>> + bool "Allwinner A23 (sun8i) SoCs support"
>> + default ARCH_SUNXI
>> + select ARCH_HAS_RESET_CONTROLLER
>> + select ARM_GIC
>> + select MFD_SUN6I_PRCM
>> + select RESET_CONTROLLER
>> +
>> endif
>> diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
>> index 3f9587b..962ff30 100644
>> --- a/arch/arm/mach-sunxi/sunxi.c
>> +++ b/arch/arm/mach-sunxi/sunxi.c
>> @@ -53,3 +53,13 @@ static const char * const sun7i_board_dt_compat[] = {
>> DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family")
>> .dt_compat = sun7i_board_dt_compat,
>> MACHINE_END
>> +
>> +static const char * const sun8i_board_dt_compat[] = {
>> + "allwinner,sun8i-a23",
>> + NULL,
>> +};
>> +
>> +DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family")
>> + .init_time = sun6i_timer_init,
>
> I haven't seen anything in your code that needed to use this
> function. Am I missing something?

(Adding Maxime back to recipients...)

My mistake. From the log I thought all timers needed the reset
controller. Turns out only the high speed timer does.

I'll remove the call in the next version.


ChenYu

2014-06-20 06:14:23

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH v2 12/20] clk: sunxi: Add A23 APB0 support to sun6i-a31-apb0-clk

On Thu, Jun 19, 2014 at 5:28 PM, Maxime Ripard
<[email protected]> wrote:
> On Thu, Jun 19, 2014 at 12:33:41PM +0800, Chen-Yu Tsai wrote:
>> On Wed, Jun 18, 2014 at 6:26 PM, Maxime Ripard
>> <[email protected]> wrote:
>> > On Tue, Jun 17, 2014 at 10:52:49PM +0800, Chen-Yu Tsai wrote:
>> >> The A23 has an almost identical PRCM clock tree. The difference in
>> >> the APB0 clock is the smallest divisor is 1, instead of 2.
>> >>
>> >> This patch extends the sun6i-a31-apb0-clk driver to take divider
>> >> tables associated to compatibles, and adds a compatible for the A23
>> >> variant.
>> >>
>> >> Signed-off-by: Chen-Yu Tsai <[email protected]>
>> >> ---
>> >> Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
>> >> drivers/clk/sunxi/clk-sun6i-apb0.c | 28 ++++++++++++++++++-----
>> >> 2 files changed, 23 insertions(+), 6 deletions(-)
>> >>
>> >> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
>> >> index af9e47d..e3a47ec 100644
>> >> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
>> >> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
>> >> @@ -28,6 +28,7 @@ Required properties:
>> >> "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
>> >> "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
>> >> "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
>> >> + "allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23
>> >> "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
>> >> "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
>> >> "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
>> >> diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c
>> >> index 11f17c3..2197ac7 100644
>> >> --- a/drivers/clk/sunxi/clk-sun6i-apb0.c
>> >> +++ b/drivers/clk/sunxi/clk-sun6i-apb0.c
>> >> @@ -11,6 +11,7 @@
>> >> #include <linux/clk-provider.h>
>> >> #include <linux/module.h>
>> >> #include <linux/of.h>
>> >> +#include <linux/of_device.h>
>> >> #include <linux/platform_device.h>
>> >>
>> >> /*
>> >> @@ -28,6 +29,21 @@ static const struct clk_div_table sun6i_a31_apb0_divs[] = {
>>
>> For reference:
>>
>> static const struct clk_div_table sun6i_a31_apb0_divs[] = {
>> { .val = 0, .div = 2, },
>> { .val = 1, .div = 2, },
>> { .val = 2, .div = 4, },
>> { .val = 3, .div = 8, },
>> { /* sentinel */ },
>> };
>>
>>
>> >> { /* sentinel */ },
>> >> };
>> >>
>> >> +/* The A23 APB0 clock has a standard power of 2 divisor */
>> >
>> > Why not just pass CLK_DIVIDER_POWER_OF_TWO then, instead of a table?
>>
>> The A31 APB0 clock uses a table for the odd /2 divisor for value 0.
>> The standard table I'm using for the A23 is just to keep it simple
>> and alike.
>>
>> >> +static const struct clk_div_table sun8i_a23_apb0_divs[] = {
>> >> + { .val = 0, .div = 1, },
>> >> + { .val = 1, .div = 2, },
>> >> + { .val = 2, .div = 4, },
>> >> + { .val = 3, .div = 8, },
>> >> + { /* sentinel */ },
>> >> +};
>> >> +
>> >> +const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = {
>> >> + { .compatible = "allwinner,sun6i-a31-apb0-clk", .data = &sun6i_a31_apb0_divs },
>> >> + { .compatible = "allwinner,sun8i-a23-apb0-clk", .data = &sun8i_a23_apb0_divs },
>> >> + { /* sentinel */ }
>> >> +};
>> >> +
>> >> static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
>> >> {
>> >> struct device_node *np = pdev->dev.of_node;
>> >> @@ -36,12 +52,17 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
>> >> struct resource *r;
>> >> void __iomem *reg;
>> >> struct clk *clk;
>> >> + const struct of_device_id *device;
>> >>
>> >> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> >> reg = devm_ioremap_resource(&pdev->dev, r);
>> >> if (IS_ERR(reg))
>> >> return PTR_ERR(reg);
>> >>
>> >> + device = of_match_device(sun6i_a31_apb0_clk_dt_ids, &pdev->dev);
>> >> + if (!device)
>> >> + return -EINVAL;
>> >> +
>> >> clk_parent = of_clk_get_parent_name(np, 0);
>> >> if (!clk_parent)
>> >> return -EINVAL;
>> >> @@ -49,7 +70,7 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
>> >> of_property_read_string(np, "clock-output-names", &clk_name);
>> >>
>> >> clk = clk_register_divider_table(&pdev->dev, clk_name, clk_parent,
>> >> - 0, reg, 0, 2, 0, sun6i_a31_apb0_divs,
>> >> + 0, reg, 0, 2, 0, device->data,
>> >
>> > I'm not sure that it will actually work for the A31, since it does
>> > define some dividers anyway, and the divider table is !NULL, even
>> > though there's actually no dividers defined.
>>
>> I'm not following. The A31 does have a table defined. It's just cut
>> off in this patch. I asked Boris to add the table when he was working
>> on the A31 PRCM clocks. See above.
>
> Ah right. My bad.
>
> If these two clocks are these different though, maybe it would just be
> easier to add a new driver. These are trivial enough anyway.

Yes it is. But it adds more of the same boilerplate code than actual
differences of the hardware.

I'm inclined to keep it as it is for now, unless someone strongly
objects.


ChenYu

2014-06-20 07:39:05

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH v2 16/20] mfd: sun6i-prcm: Add support for Allwinner A23 PRCM

On Wed, Jun 18, 2014 at 8:24 PM, Maxime Ripard
<[email protected]> wrote:
> On Wed, Jun 18, 2014 at 09:29:53AM +0100, Lee Jones wrote:
>> > The Allwinner A23 SoC has a PRCM unit like the previous A31 SoC.
>> > The differences are the AR100 clock can no longer be modified,
>> > the APB0 clock has different divisors, and some clock gates are
>> > gone.
>> >
>> > This patch adds a compatible with a modified subdevice list for
>> > the A23.
>> >
>> > Signed-off-by: Chen-Yu Tsai <[email protected]>
>> > ---
>> > .../devicetree/bindings/mfd/sun6i-prcm.txt | 2 +-
>> > drivers/mfd/sun6i-prcm.c | 30 ++++++++++++++++++++++
>> > 2 files changed, 31 insertions(+), 1 deletion(-)
>>
>> The patch looks fine to me, but I'm concerned about the size of the
>> patch set and the amount of subsystems it touches.
>>
>> I am guessing that this patch can just be taken independently though.
>> Please correct me if I'm wrong.
>
> I have a bit of the same concern. We have several comments on the
> previous patches, so I'm not even sure this patch can go as is.
>
> It would be much easier if you (ChenYu) could introduce first a very
> basic with just the UART support, and then, as separate series,
> clocks, PRCM, MMC, and so on.

OK. I will do that. I'll also try to send some of the independent
fixes separately.


ChenYu

2014-06-23 04:44:51

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH v2 09/20] clk: sunxi: Add sun6i MBUS clock support

On Wed, Jun 18, 2014 at 6:04 PM, Maxime Ripard
<[email protected]> wrote:
> On Tue, Jun 17, 2014 at 10:52:46PM +0800, Chen-Yu Tsai wrote:
>> Signed-off-by: Chen-Yu Tsai <[email protected]>
>> ---
>> Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
>> drivers/clk/sunxi/clk-sunxi.c | 44 +++++++++++++++++++++++
>> 2 files changed, 45 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
>> index b9ec668..7b2ba41 100644
>> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
>> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
>> @@ -40,6 +40,7 @@ Required properties:
>> "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
>> "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
>> "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
>> + "allwinner,sun6i-a31-mbus-clk" - for the MBUS clocks on A31 / A23
>> "allwinner,sun7i-a20-out-clk" - for the external output clocks
>> "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
>> "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
>> diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
>> index eca3c6e..a086b5b 100644
>> --- a/drivers/clk/sunxi/clk-sunxi.c
>> +++ b/drivers/clk/sunxi/clk-sunxi.c
>> @@ -307,6 +307,37 @@ static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate,
>>
>>
>> /**
>> + * sun6i_a31_get_mbus_factors() - calculates m factor for MBUS clocks
>> + * MBUS rate is calculated as follows
>> + * rate = parent_rate / (m + 1);
>> + */
>> +
>> +static void sun6i_a31_get_mbus_factors(u32 *freq, u32 parent_rate,
>> + u8 *n, u8 *k, u8 *m, u8 *p)
>> +{
>> + u8 div;
>> +
>> + /* These clocks can only divide, so we will never be able to achieve
>> + * frequencies higher than the parent frequency */
>> + if (*freq > parent_rate)
>> + *freq = parent_rate;
>> +
>> + div = DIV_ROUND_UP(parent_rate, *freq);
>> +
>> + if (div > 8)
>> + div = 8;
>> +
>> + *freq = parent_rate / div;
>> +
>> + /* we were called to round the frequency, we can now return */
>> + if (n == NULL)
>
> s/n/m/ ?

The factors clk driver passes all or none pointers.
But I will change this to avoid the confusion.

>> + return;
>> +
>> + *m = div - 1;
>> +}
>> +
>> +
>> +/**
>> * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B
>> * CLK_OUT rate is calculated as follows
>> * rate = (parent_rate >> p) / (m + 1);
>> @@ -447,6 +478,11 @@ static struct clk_factors_config sun4i_mod0_config = {
>> .pwidth = 2,
>> };
>>
>> +static struct clk_factors_config sun6i_a31_mbus_config = {
>> + .mshift = 0,
>> + .mwidth = 3,
>
> Actually, the A31 has an extra N factor.
>
> So this mbus clock looks like it's only about the A23, and not the A31
> at all.

I checked original sun6i code and sun6i code found in the A23 SDK.
The original code uses the module 0 clock driver for mbus, so yes
there's an extra N factor. The new code in the A23 SDK does not.

Unfortunately I haven't been able to get my Hummingbird A31 up yet,
so I can't poke around to check it.


ChenYu

2014-06-25 16:45:12

by Maxime Ripard

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH v2 12/20] clk: sunxi: Add A23 APB0 support to sun6i-a31-apb0-clk

On Fri, Jun 20, 2014 at 02:13:58PM +0800, Chen-Yu Tsai wrote:
> > If these two clocks are these different though, maybe it would just be
> > easier to add a new driver. These are trivial enough anyway.
>
> Yes it is. But it adds more of the same boilerplate code than actual
> differences of the hardware.
>
> I'm inclined to keep it as it is for now, unless someone strongly
> objects.

I'm not strongly objecting, but I'd strongly prefer to go with two
drivers.

I don't really want to end up in the same case than with clk-sunxi.c,
which handles a lot of weird corner case for one particular clock,
while most of them are just a single-bit gate.

Especially when they have nothing in common, which is pretty much the
case here.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (849.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-07-07 13:00:10

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v2 14/20] pinctrl: sunxi: Add A23 PIO controller support

On Tue, Jun 17, 2014 at 4:52 PM, Chen-Yu Tsai <[email protected]> wrote:

> The A23 uses the same pin controller as previous SoC's from Allwinner.
> Add support for the pins controlled by the main PIO controller.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> Acked-by: Maxime Ripard <[email protected]>

Patch applied, thanks!

Yours,
Linus Walleij

2014-07-07 13:17:54

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v2 15/20] pinctrl: sunxi: Add A23 R_PIO controller support

On Tue, Jun 17, 2014 at 4:52 PM, Chen-Yu Tsai <[email protected]> wrote:

> The A23 has a R_PIO pin controller, similar to the one found on the A31 SoC.
> Add support for the pins controlled by the R_PIO controller.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> Acked-by: Maxime Ripard <[email protected]>

Patch applied.

Yours,
Linus Walleij