Commit 2fbae64a authored by Stephen Boyd's avatar Stephen Boyd

Merge tag 'sunxi-clk-for-4.11' of...

Merge tag 'sunxi-clk-for-4.11' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into clk-next

Pull Allwinner clock updates from Maxime Ripard:

  - Support for one new SoC, the V3s
  - Conversion of two old SoCs to the new framework, the old sun5i family
    and the A80
  - A bunch of fixes

* tag 'sunxi-clk-for-4.11' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux: (25 commits)
  ARM: dts: sun9i: Switch to new clock bindings
  clk: sunxi-ng: Add A80 Display Engine CCU
  clk: sunxi-ng: Add A80 USB CCU
  clk: sunxi-ng: Add A80 CCU
  clk: sunxi-ng: Support separately grouped PLL lock status register
  clk: sunxi-ng: mux: Get closest parent rate possible with CLK_SET_RATE_PARENT
  clk: sunxi-ng: mux: honor CLK_SET_RATE_NO_REPARENT flag
  clk: sunxi-ng: mux: Fix determine_rate for mux clocks with pre-dividers
  clk: sunxi-ng: a33: Set CLK_SET_RATE_PARENT for the GPU
  clk: sunxi-ng: Call divider_round_rate if we only have a single parent
  ARM: gr8: Convert to CCU
  ARM: sun5i: Convert to CCU
  clk: sunxi-ng: Add sun5i CCU driver
  clk: sunxi-ng: Implement global pre-divider
  clk: sunxi-ng: Implement multiplier maximum
  clk: sunxi-ng: mult: Fix minimum in round rate
  clk: sunxi-ng: Implement factors offsets
  clk: sunxi-ng: multiplier: Add fractional support
  clk: sunxi-ng: add support for V3s CCU
  dt-bindings: add device binding for the CCU of Allwinner V3s
  ...
parents eaff16bc 64507fe3
Allwinner A80 Display Engine Clock Control Binding
--------------------------------------------------
Required properties :
- compatible: must contain one of the following compatibles:
- "allwinner,sun9i-a80-de-clks"
- reg: Must contain the registers base address and length
- clocks: phandle to the clocks feeding the display engine subsystem.
Three are needed:
- "mod": the display engine module clock
- "dram": the DRAM bus clock for the system
- "bus": the bus clock for the whole display engine subsystem
- clock-names: Must contain the clock names described just above
- resets: phandle to the reset control for the display engine subsystem.
- #clock-cells : must contain 1
- #reset-cells : must contain 1
Example:
de_clocks: clock@3000000 {
compatible = "allwinner,sun9i-a80-de-clks";
reg = <0x03000000 0x30>;
clocks = <&ccu CLK_DE>, <&ccu CLK_SDRAM>, <&ccu CLK_BUS_DE>;
clock-names = "mod", "dram", "bus";
resets = <&ccu RST_BUS_DE>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Allwinner A80 USB Clock Control Binding
---------------------------------------
Required properties :
- compatible: must contain one of the following compatibles:
- "allwinner,sun9i-a80-usb-clocks"
- reg: Must contain the registers base address and length
- clocks: phandle to the clocks feeding the USB subsystem. Two are needed:
- "bus": the bus clock for the whole USB subsystem
- "hosc": the high frequency oscillator (usually at 24MHz)
- clock-names: Must contain the clock names described just above
- #clock-cells : must contain 1
- #reset-cells : must contain 1
Example:
usb_clocks: clock@a08000 {
compatible = "allwinner,sun9i-a80-usb-clks";
reg = <0x00a08000 0x8>;
clocks = <&ccu CLK_BUS_USB>, <&osc24M>;
clock-names = "bus", "hosc";
#clock-cells = <1>;
#reset-cells = <1>;
};
......@@ -7,6 +7,8 @@ Required properties :
- "allwinner,sun8i-a23-ccu"
- "allwinner,sun8i-a33-ccu"
- "allwinner,sun8i-h3-ccu"
- "allwinner,sun8i-v3s-ccu"
- "allwinner,sun9i-a80-ccu"
- "allwinner,sun50i-a64-ccu"
- reg: Must contain the registers base address and length
......
......@@ -65,8 +65,9 @@ framebuffer@0 {
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
clocks = <&pll3>, <&pll5 1>, <&ahb_gates 36>,
<&ahb_gates 43>, <&ahb_gates 44>;
clocks = <&ccu CLK_AHB_LCD>, <&ccu CLK_AHB_HDMI>,
<&ccu CLK_AHB_DE_BE>, <&ccu CLK_DRAM_DE_BE>,
<&ccu CLK_DE_BE>, <&ccu CLK_HDMI>;
status = "disabled";
};
......@@ -74,8 +75,8 @@ framebuffer@1 {
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0";
clocks = <&pll3>, <&pll5 1>, <&ahb_gates 36>,
<&ahb_gates 44>;
clocks = <&ccu CLK_AHB_LCD>, <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>,
<&ccu CLK_TCON_CH0>, <&ccu CLK_DRAM_DE_BE>;
status = "disabled";
};
......@@ -83,77 +84,19 @@ framebuffer@2 {
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-tve0";
clocks = <&pll3>, <&pll5 1>, <&ahb_gates 34>,
<&ahb_gates 36>, <&ahb_gates 44>;
clocks = <&ccu CLK_AHB_TVE>, <&ccu CLK_AHB_LCD>,
<&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>,
<&ccu CLK_TCON_CH1>, <&ccu CLK_DRAM_DE_BE>;
status = "disabled";
};
};
clocks {
ahb_gates: clk@01c20060 {
#clock-cells = <1>;
compatible = "allwinner,sun5i-a10s-ahb-gates-clk";
reg = <0x01c20060 0x8>;
clocks = <&ahb>;
clock-indices = <0>, <1>,
<2>, <5>, <6>,
<7>, <8>, <9>,
<10>, <13>,
<14>, <17>, <18>,
<20>, <21>, <22>,
<26>, <28>, <32>,
<34>, <36>, <40>,
<43>, <44>,
<46>, <51>,
<52>;
clock-output-names = "ahb_usbotg", "ahb_ehci",
"ahb_ohci", "ahb_ss", "ahb_dma",
"ahb_bist", "ahb_mmc0", "ahb_mmc1",
"ahb_mmc2", "ahb_nand",
"ahb_sdram", "ahb_emac", "ahb_ts",
"ahb_spi0", "ahb_spi1", "ahb_spi2",
"ahb_gps", "ahb_stimer", "ahb_ve",
"ahb_tve", "ahb_lcd", "ahb_csi",
"ahb_hdmi", "ahb_de_be",
"ahb_de_fe", "ahb_iep",
"ahb_mali400";
};
apb0_gates: clk@01c20068 {
#clock-cells = <1>;
compatible = "allwinner,sun5i-a10s-apb0-gates-clk";
reg = <0x01c20068 0x4>;
clocks = <&apb0>;
clock-indices = <0>, <3>,
<5>, <6>,
<10>;
clock-output-names = "apb0_codec", "apb0_iis",
"apb0_pio", "apb0_ir",
"apb0_keypad";
};
apb1_gates: clk@01c2006c {
#clock-cells = <1>;
compatible = "allwinner,sun5i-a10s-apb1-gates-clk";
reg = <0x01c2006c 0x4>;
clocks = <&apb1>;
clock-indices = <0>, <1>,
<2>, <16>,
<17>, <18>,
<19>;
clock-output-names = "apb1_i2c0", "apb1_i2c1",
"apb1_i2c2", "apb1_uart0",
"apb1_uart1", "apb1_uart2",
"apb1_uart3";
};
};
soc@01c00000 {
emac: ethernet@01c0b000 {
compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <55>;
clocks = <&ahb_gates 17>;
clocks = <&ccu CLK_AHB_EMAC>;
allwinner,sram = <&emac_sram 1>;
status = "disabled";
};
......@@ -169,7 +112,7 @@ mdio: mdio@01c0b080 {
pwm: pwm@01c20e00 {
compatible = "allwinner,sun5i-a10s-pwm";
reg = <0x01c20e00 0xc>;
clocks = <&osc24M>;
clocks = <&ccu CLK_HOSC>;
#pwm-cells = <3>;
status = "disabled";
};
......@@ -180,7 +123,7 @@ uart0: serial@01c28000 {
interrupts = <1>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&apb1_gates 16>;
clocks = <&ccu CLK_APB1_UART0>;
status = "disabled";
};
......@@ -190,12 +133,16 @@ uart2: serial@01c28800 {
interrupts = <3>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&apb1_gates 18>;
clocks = <&ccu CLK_APB1_UART2>;
status = "disabled";
};
};
};
&ccu {
compatible = "allwinner,sun5i-a10s-ccu";
};
&pio {
compatible = "allwinner,sun5i-a10s-pinctrl";
......
......@@ -61,8 +61,8 @@ framebuffer@0 {
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0";
clocks = <&ahb_gates 36>, <&ahb_gates 44>, <&de_be_clk>,
<&tcon_ch0_clk>, <&dram_gates 26>;
clocks = <&ccu CLK_AHB_LCD>, <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>,
<&ccu CLK_TCON_CH0>, <&ccu CLK_DRAM_DE_BE>;
status = "disabled";
};
};
......@@ -99,114 +99,6 @@ cpu_crit: cpu_crit {
};
};
clocks {
ahb_gates: clk@01c20060 {
#clock-cells = <1>;
compatible = "allwinner,sun5i-a13-ahb-gates-clk";
reg = <0x01c20060 0x8>;
clocks = <&ahb>;
clock-indices = <0>, <1>,
<2>, <5>, <6>,
<7>, <8>, <9>,
<10>, <13>,
<14>, <20>,
<21>, <22>,
<28>, <32>, <34>,
<36>, <40>, <44>,
<46>, <51>,
<52>;
clock-output-names = "ahb_usbotg", "ahb_ehci",
"ahb_ohci", "ahb_ss", "ahb_dma",
"ahb_bist", "ahb_mmc0", "ahb_mmc1",
"ahb_mmc2", "ahb_nand",
"ahb_sdram", "ahb_spi0",
"ahb_spi1", "ahb_spi2",
"ahb_stimer", "ahb_ve", "ahb_tve",
"ahb_lcd", "ahb_csi", "ahb_de_be",
"ahb_de_fe", "ahb_iep",
"ahb_mali400";
};
apb0_gates: clk@01c20068 {
#clock-cells = <1>;
compatible = "allwinner,sun5i-a13-apb0-gates-clk";
reg = <0x01c20068 0x4>;
clocks = <&apb0>;
clock-indices = <0>, <5>,
<6>;
clock-output-names = "apb0_codec", "apb0_pio",
"apb0_ir";
};
apb1_gates: clk@01c2006c {
#clock-cells = <1>;
compatible = "allwinner,sun5i-a13-apb1-gates-clk";
reg = <0x01c2006c 0x4>;
clocks = <&apb1>;
clock-indices = <0>, <1>,
<2>, <17>,
<19>;
clock-output-names = "apb1_i2c0", "apb1_i2c1",
"apb1_i2c2", "apb1_uart1",
"apb1_uart3";
};
dram_gates: clk@01c20100 {
#clock-cells = <1>;
compatible = "allwinner,sun5i-a13-dram-gates-clk",
"allwinner,sun4i-a10-gates-clk";
reg = <0x01c20100 0x4>;
clocks = <&pll5 0>;
clock-indices = <0>,
<1>,
<25>,
<26>,
<29>,
<31>;
clock-output-names = "dram_ve",
"dram_csi",
"dram_de_fe",
"dram_de_be",
"dram_ace",
"dram_iep";
};
de_be_clk: clk@01c20104 {
#clock-cells = <0>;
#reset-cells = <0>;
compatible = "allwinner,sun4i-a10-display-clk";
reg = <0x01c20104 0x4>;
clocks = <&pll3>, <&pll7>, <&pll5 1>;
clock-output-names = "de-be";
};
de_fe_clk: clk@01c2010c {
#clock-cells = <0>;
#reset-cells = <0>;
compatible = "allwinner,sun4i-a10-display-clk";
reg = <0x01c2010c 0x4>;
clocks = <&pll3>, <&pll7>, <&pll5 1>;
clock-output-names = "de-fe";
};
tcon_ch0_clk: clk@01c20118 {
#clock-cells = <0>;
#reset-cells = <1>;
compatible = "allwinner,sun4i-a10-tcon-ch0-clk";
reg = <0x01c20118 0x4>;
clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
clock-output-names = "tcon-ch0-sclk";
};
tcon_ch1_clk: clk@01c2012c {
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-tcon-ch1-clk";
reg = <0x01c2012c 0x4>;
clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
clock-output-names = "tcon-ch1-sclk";
};
};
display-engine {
compatible = "allwinner,sun5i-a13-display-engine";
allwinner,pipelines = <&fe0>;
......@@ -217,11 +109,11 @@ tcon0: lcd-controller@01c0c000 {
compatible = "allwinner,sun5i-a13-tcon";
reg = <0x01c0c000 0x1000>;
interrupts = <44>;
resets = <&tcon_ch0_clk 1>;
resets = <&ccu RST_LCD>;
reset-names = "lcd";
clocks = <&ahb_gates 36>,
<&tcon_ch0_clk>,
<&tcon_ch1_clk>;
clocks = <&ccu CLK_AHB_LCD>,
<&ccu CLK_TCON_CH0>,
<&ccu CLK_TCON_CH1>;
clock-names = "ahb",
"tcon-ch0",
"tcon-ch1";
......@@ -254,7 +146,7 @@ tcon0_out: port@1 {
pwm: pwm@01c20e00 {
compatible = "allwinner,sun5i-a13-pwm";
reg = <0x01c20e00 0xc>;
clocks = <&osc24M>;
clocks = <&ccu CLK_HOSC>;
#pwm-cells = <3>;
status = "disabled";
};
......@@ -263,11 +155,11 @@ fe0: display-frontend@01e00000 {
compatible = "allwinner,sun5i-a13-display-frontend";
reg = <0x01e00000 0x20000>;
interrupts = <47>;
clocks = <&ahb_gates 46>, <&de_fe_clk>,
<&dram_gates 25>;
clocks = <&ccu CLK_DE_FE>, <&ccu CLK_DE_FE>,
<&ccu CLK_DRAM_DE_FE>;
clock-names = "ahb", "mod",
"ram";
resets = <&de_fe_clk>;
resets = <&ccu RST_DE_FE>;
status = "disabled";
ports {
......@@ -290,14 +182,14 @@ fe0_out_be0: endpoint@0 {
be0: display-backend@01e60000 {
compatible = "allwinner,sun5i-a13-display-backend";
reg = <0x01e60000 0x10000>;
clocks = <&ahb_gates 44>, <&de_be_clk>,
<&dram_gates 26>;
clocks = <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>,
<&ccu CLK_DRAM_DE_BE>;
clock-names = "ahb", "mod",
"ram";
resets = <&de_be_clk>;
resets = <&ccu RST_DE_BE>;
status = "disabled";
assigned-clocks = <&de_be_clk>;
assigned-clocks = <&ccu CLK_DE_BE>;
assigned-clock-rates = <300000000>;
ports {
......@@ -330,6 +222,10 @@ be0_out_tcon0: endpoint@0 {
};
};
&ccu {
compatible = "allwinner,sun5i-a13-ccu";
};
&cpu0 {
clock-latency = <244144>; /* 8 32k periods */
operating-points = <
......
This diff is collapsed.
......@@ -51,9 +51,9 @@ framebuffer@1 {
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-tve0";
clocks = <&ahb_gates 34>, <&ahb_gates 36>,
<&ahb_gates 44>, <&de_be_clk>,
<&tcon_ch1_clk>, <&dram_gates 26>;
clocks = <&ccu CLK_AHB_TVE>, <&ccu CLK_AHB_LCD>,
<&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>,
<&ccu CLK_TCON_CH1>, <&ccu CLK_DRAM_DE_BE>;
status = "disabled";
};
};
......@@ -62,8 +62,8 @@ soc@01c00000 {
tve0: tv-encoder@01c0a000 {
compatible = "allwinner,sun4i-a10-tv-encoder";
reg = <0x01c0a000 0x1000>;
clocks = <&ahb_gates 34>;
resets = <&tcon_ch0_clk 0>;
clocks = <&ccu CLK_AHB_TVE>;
resets = <&ccu RST_TVE>;
status = "disabled";
port {
......
This diff is collapsed.
This diff is collapsed.
......@@ -64,6 +64,16 @@ config SUN50I_A64_CCU
select SUNXI_CCU_PHASE
default ARM64 && ARCH_SUNXI
config SUN5I_CCU
bool "Support for the Allwinner sun5i family CCM"
select SUNXI_CCU_DIV
select SUNXI_CCU_NK
select SUNXI_CCU_NKM
select SUNXI_CCU_NM
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN5I
config SUN6I_A31_CCU
bool "Support for the Allwinner A31/A31s CCU"
select SUNXI_CCU_DIV
......@@ -109,4 +119,25 @@ config SUN8I_H3_CCU
select SUNXI_CCU_PHASE
default MACH_SUN8I
config SUN8I_V3S_CCU
bool "Support for the Allwinner V3s CCU"
select SUNXI_CCU_DIV
select SUNXI_CCU_NK
select SUNXI_CCU_NKM
select SUNXI_CCU_NKMP
select SUNXI_CCU_NM
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN8I
config SUN9I_A80_CCU
bool "Support for the Allwinner A80 CCU"
select SUNXI_CCU_DIV
select SUNXI_CCU_GATE
select SUNXI_CCU_NKMP
select SUNXI_CCU_NM
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN9I
endif
......@@ -19,7 +19,12 @@ obj-$(CONFIG_SUNXI_CCU_MP) += ccu_mp.o
# SoC support
obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o
obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o
obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o
obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o
obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o
obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o
obj-$(CONFIG_SUN8I_V3S_CCU) += ccu-sun8i-v3s.o
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80.o
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80-de.o
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80-usb.o
This diff is collapsed.
/*
* Copyright 2016 Maxime Ripard
*
* Maxime Ripard <maxime.ripard@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_SUN5I_H_
#define _CCU_SUN5I_H_
#include <dt-bindings/clock/sun5i-ccu.h>
#include <dt-bindings/reset/sun5i-ccu.h>
/* The HOSC is exported */
#define CLK_PLL_CORE 2
#define CLK_PLL_AUDIO_BASE 3
#define CLK_PLL_AUDIO 4
#define CLK_PLL_AUDIO_2X 5
#define CLK_PLL_AUDIO_4X 6
#define CLK_PLL_AUDIO_8X 7
#define CLK_PLL_VIDEO0 8
#define CLK_PLL_VIDEO0_2X 9
#define CLK_PLL_VE 10
#define CLK_PLL_DDR_BASE 11
#define CLK_PLL_DDR 12
#define CLK_PLL_DDR_OTHER 13
#define CLK_PLL_PERIPH 14
#define CLK_PLL_VIDEO1 15
#define CLK_PLL_VIDEO1_2X 16
/* The CPU clock is exported */
#define CLK_AXI 18
#define CLK_AHB 19
#define CLK_APB0 20
#define CLK_APB1 21
#define CLK_DRAM_AXI 22
/* AHB gates are exported */
/* APB0 gates are exported */
/* APB1 gates are exported */
/* Modules clocks are exported */
/* USB clocks are exported */
/* GPS clock is exported */
/* DRAM gates are exported */
/* More display modules clocks are exported */
#define CLK_TCON_CH1_SCLK 91
/* The rest of the module clocks are exported */
#define CLK_MBUS 99
/* And finally the IEP clock */
#define CLK_NUMBER (CLK_IEP + 1)
#endif /* _CCU_SUN5I_H_ */
......@@ -468,8 +468,8 @@ static SUNXI_CCU_MUX_WITH_GATE(daudio0_clk, "daudio0", daudio_parents,
static SUNXI_CCU_MUX_WITH_GATE(daudio1_clk, "daudio1", daudio_parents,
0x0b4, 16, 2, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio",
0x0c0, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_MUX_WITH_GATE(spdif_clk, "spdif", daudio_parents,
0x0c0, 16, 2, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M",
0x0cc, BIT(8), 0);
......
......@@ -170,7 +170,7 @@ static SUNXI_CCU_N_WITH_GATE_LOCK(pll_ddr1_clk, "pll-ddr1",
static const char * const cpux_parents[] = { "osc32k", "osc24M",
"pll-cpux" , "pll-cpux" };
static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents,
0x050, 16, 2, CLK_IS_CRITICAL);
0x050, 16, 2, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT);
static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x050, 0, 2, 0);
......@@ -440,7 +440,7 @@ static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve",
0x13c, 16, 3, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio",
0x140, BIT(31), 0);
0x140, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_GATE(ac_dig_4x_clk, "ac-dig-4x", "pll-audio-4x",
0x140, BIT(30), 0);
static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M",
......@@ -468,7 +468,7 @@ static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(drc_clk, "drc",
0x180, 0, 4, 24, 3, BIT(31), 0);
static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu",
0x1a0, 0, 3, BIT(31), 0);
0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT);
static const char * const ats_parents[] = { "osc24M", "pll-periph" };
static SUNXI_CCU_M_WITH_MUX_GATE(ats_clk, "ats", ats_parents,
......@@ -752,6 +752,13 @@ static const struct sunxi_ccu_desc sun8i_a33_ccu_desc = {
.num_resets = ARRAY_SIZE(sun8i_a33_ccu_resets),
};
static struct ccu_mux_nb sun8i_a33_cpu_nb = {
.common = &cpux_clk.common,
.cm = &cpux_clk.mux,
.delay_us = 1, /* > 8 clock cycles at 24 MHz */
.bypass_index = 1, /* index of 24 MHz oscillator */
};
static void __init sun8i_a33_ccu_setup(struct device_node *node)
{
void __iomem *reg;
......@@ -775,6 +782,9 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
writel(val, reg + SUN8I_A33_PLL_MIPI_REG);
sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc);
ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
&sun8i_a33_cpu_nb);
}
CLK_OF_DECLARE(sun8i_a33_ccu, "allwinner,sun8i-a33-ccu",
sun8i_a33_ccu_setup);
......@@ -803,6 +803,13 @@ static const struct sunxi_ccu_desc sun8i_h3_ccu_desc = {
.num_resets = ARRAY_SIZE(sun8i_h3_ccu_resets),
};
static struct ccu_mux_nb sun8i_h3_cpu_nb = {
.common = &cpux_clk.common,
.cm = &cpux_clk.mux,
.delay_us = 1, /* > 8 clock cycles at 24 MHz */
.bypass_index = 1, /* index of 24 MHz oscillator */
};
static void __init sun8i_h3_ccu_setup(struct device_node *node)
{
void __iomem *reg;
......@@ -821,6 +828,9 @@ static void __init sun8i_h3_ccu_setup(struct device_node *node)
writel(val | (3 << 16), reg + SUN8I_H3_PLL_AUDIO_REG);
sunxi_ccu_probe(node, reg, &sun8i_h3_ccu_desc);
ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
&sun8i_h3_cpu_nb);
}
CLK_OF_DECLARE(sun8i_h3_ccu, "allwinner,sun8i-h3-ccu",
sun8i_h3_ccu_setup);
This diff is collapsed.
/*
* Copyright (c) 2016 Icenowy Zheng <icenowy@aosc.xyz>
*
* Based on ccu-sun8i-h3.h, which is:
* Copyright (c) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_SUN8I_H3_H_
#define _CCU_SUN8I_H3_H_
#include <dt-bindings/clock/sun8i-v3s-ccu.h>
#include <dt-bindings/reset/sun8i-v3s-ccu.h>
#define CLK_PLL_CPU 0
#define CLK_PLL_AUDIO_BASE 1
#define CLK_PLL_AUDIO 2
#define CLK_PLL_AUDIO_2X 3
#define CLK_PLL_AUDIO_4X 4
#define CLK_PLL_AUDIO_8X 5
#define CLK_PLL_VIDEO 6
#define CLK_PLL_VE 7
#define CLK_PLL_DDR 8
#define CLK_PLL_PERIPH0 9
#define CLK_PLL_PERIPH0_2X 10
#define CLK_PLL_ISP 11
#define CLK_PLL_PERIPH1 12
/* Reserve one number for not implemented and not used PLL_DDR1 */
/* The CPU clock is exported */
#define CLK_AXI 15
#define CLK_AHB1 16
#define CLK_APB1 17
#define CLK_APB2 18
#define CLK_AHB2 19
/* All the bus gates are exported */
/* The first bunch of module clocks are exported */
#define CLK_DRAM 58
/* All the DRAM gates are exported */
/* Some more module clocks are exported */
#define CLK_MBUS 72
/* And the GPU module clock is exported */
#define CLK_NUMBER (CLK_MIPI_CSI + 1)
#endif /* _CCU_SUN8I_H3_H_ */
/*
* Copyright (c) 2016 Chen-Yu Tsai. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include "ccu_common.h"
#include "ccu_div.h"
#include "ccu_gate.h"
#include "ccu_reset.h"
#include "ccu-sun9i-a80-de.h"
static SUNXI_CCU_GATE(fe0_clk, "fe0", "fe0-div",
0x00, BIT(0), 0);
static SUNXI_CCU_GATE(fe1_clk, "fe1", "fe1-div",
0x00, BIT(1), 0);
static SUNXI_CCU_GATE(fe2_clk, "fe2", "fe2-div",
0x00, BIT(2), 0);
static SUNXI_CCU_GATE(iep_deu0_clk, "iep-deu0", "de",
0x00, BIT(4), 0);
static SUNXI_CCU_GATE(iep_deu1_clk, "iep-deu1", "de",
0x00, BIT(5), 0);
static SUNXI_CCU_GATE(be0_clk, "be0", "be0-div",
0x00, BIT(8), 0);
static SUNXI_CCU_GATE(be1_clk, "be1", "be1-div",
0x00, BIT(9), 0);
static SUNXI_CCU_GATE(be2_clk, "be2", "be2-div",
0x00, BIT(10), 0);
static SUNXI_CCU_GATE(iep_drc0_clk, "iep-drc0", "de",
0x00, BIT(12), 0);
static SUNXI_CCU_GATE(iep_drc1_clk, "iep-drc1", "de",
0x00, BIT(13), 0);
static SUNXI_CCU_GATE(merge_clk, "merge", "de",
0x00, BIT(20), 0);
static SUNXI_CCU_GATE(dram_fe0_clk, "dram-fe0", "sdram",
0x04, BIT(0), 0);
static SUNXI_CCU_GATE(dram_fe1_clk, "dram-fe1", "sdram",
0x04, BIT(1), 0);
static SUNXI_CCU_GATE(dram_fe2_clk, "dram-fe2", "sdram",
0x04, BIT(2), 0);
static SUNXI_CCU_GATE(dram_deu0_clk, "dram-deu0", "sdram",
0x04, BIT(4), 0);
static SUNXI_CCU_GATE(dram_deu1_clk, "dram-deu1", "sdram",
0x04, BIT(5), 0);
static SUNXI_CCU_GATE(dram_be0_clk, "dram-be0", "sdram",
0x04, BIT(8), 0);
static SUNXI_CCU_GATE(dram_be1_clk, "dram-be1", "sdram",
0x04, BIT(9), 0);
static SUNXI_CCU_GATE(dram_be2_clk, "dram-be2", "sdram",
0x04, BIT(10), 0);
static SUNXI_CCU_GATE(dram_drc0_clk, "dram-drc0", "sdram",
0x04, BIT(12), 0);
static SUNXI_CCU_GATE(dram_drc1_clk, "dram-drc1", "sdram",
0x04, BIT(13), 0);
static SUNXI_CCU_GATE(bus_fe0_clk, "bus-fe0", "bus-de",
0x08, BIT(0), 0);
static SUNXI_CCU_GATE(bus_fe1_clk, "bus-fe1", "bus-de",
0x08, BIT(1), 0);
static SUNXI_CCU_GATE(bus_fe2_clk, "bus-fe2", "bus-de",
0x08, BIT(2), 0);
static SUNXI_CCU_GATE(bus_deu0_clk, "bus-deu0", "bus-de",
0x08, BIT(4), 0);
static SUNXI_CCU_GATE(bus_deu1_clk, "bus-deu1", "bus-de",
0x08, BIT(5), 0);
static SUNXI_CCU_GATE(bus_be0_clk, "bus-be0", "bus-de",
0x08, BIT(8), 0);
static SUNXI_CCU_GATE(bus_be1_clk, "bus-be1", "bus-de",
0x08, BIT(9), 0);
static SUNXI_CCU_GATE(bus_be2_clk, "bus-be2", "bus-de",
0x08, BIT(10), 0);
static SUNXI_CCU_GATE(bus_drc0_clk, "bus-drc0", "bus-de",
0x08, BIT(12), 0);
static SUNXI_CCU_GATE(bus_drc1_clk, "bus-drc1", "bus-de",
0x08, BIT(13), 0);
static SUNXI_CCU_M(fe0_div_clk, "fe0-div", "de", 0x20, 0, 4, 0);
static SUNXI_CCU_M(fe1_div_clk, "fe1-div", "de", 0x20, 4, 4, 0);
static SUNXI_CCU_M(fe2_div_clk, "fe2-div", "de", 0x20, 8, 4, 0);
static SUNXI_CCU_M(be0_div_clk, "be0-div", "de", 0x20, 16, 4, 0);
static SUNXI_CCU_M(be1_div_clk, "be1-div", "de", 0x20, 20, 4, 0);
static SUNXI_CCU_M(be2_div_clk, "be2-div", "de", 0x20, 24, 4, 0);
static struct ccu_common *sun9i_a80_de_clks[] = {
&fe0_clk.common,
&fe1_clk.common,
&fe2_clk.common,
&iep_deu0_clk.common,
&iep_deu1_clk.common,
&be0_clk.common,
&be1_clk.common,
&be2_clk.common,
&iep_drc0_clk.common,
&iep_drc1_clk.common,
&merge_clk.common,
&dram_fe0_clk.common,
&dram_fe1_clk.common,
&dram_fe2_clk.common,
&dram_deu0_clk.common,
&dram_deu1_clk.common,
&dram_be0_clk.common,
&dram_be1_clk.common,
&dram_be2_clk.common,
&dram_drc0_clk.common,
&dram_drc1_clk.common,
&bus_fe0_clk.common,
&bus_fe1_clk.common,
&bus_fe2_clk.common,
&bus_deu0_clk.common,
&bus_deu1_clk.common,
&bus_be0_clk.common,
&bus_be1_clk.common,
&bus_be2_clk.common,
&bus_drc0_clk.common,
&bus_drc1_clk.common,
&fe0_div_clk.common,
&fe1_div_clk.common,
&fe2_div_clk.common,
&be0_div_clk.common,
&be1_div_clk.common,
&be2_div_clk.common,
};
static struct clk_hw_onecell_data sun9i_a80_de_hw_clks = {
.hws = {
[CLK_FE0] = &fe0_clk.common.hw,
[CLK_FE1] = &fe1_clk.common.hw,
[CLK_FE2] = &fe2_clk.common.hw,
[CLK_IEP_DEU0] = &iep_deu0_clk.common.hw,
[CLK_IEP_DEU1] = &iep_deu1_clk.common.hw,
[CLK_BE0] = &be0_clk.common.hw,
[CLK_BE1] = &be1_clk.common.hw,
[CLK_BE2] = &be2_clk.common.hw,
[CLK_IEP_DRC0] = &iep_drc0_clk.common.hw,
[CLK_IEP_DRC1] = &iep_drc1_clk.common.hw,
[CLK_MERGE] = &merge_clk.common.hw,
[CLK_DRAM_FE0] = &dram_fe0_clk.common.hw,
[CLK_DRAM_FE1] = &dram_fe1_clk.common.hw,
[CLK_DRAM_FE2] = &dram_fe2_clk.common.hw,
[CLK_DRAM_DEU0] = &dram_deu0_clk.common.hw,
[CLK_DRAM_DEU1] = &dram_deu1_clk.common.hw,
[CLK_DRAM_BE0] = &dram_be0_clk.common.hw,
[CLK_DRAM_BE1] = &dram_be1_clk.common.hw,
[CLK_DRAM_BE2] = &dram_be2_clk.common.hw,
[CLK_DRAM_DRC0] = &dram_drc0_clk.common.hw,
[CLK_DRAM_DRC1] = &dram_drc1_clk.common.hw,
[CLK_BUS_FE0] = &bus_fe0_clk.common.hw,
[CLK_BUS_FE1] = &bus_fe1_clk.common.hw,
[CLK_BUS_FE2] = &bus_fe2_clk.common.hw,
[CLK_BUS_DEU0] = &bus_deu0_clk.common.hw,
[CLK_BUS_DEU1] = &bus_deu1_clk.common.hw,
[CLK_BUS_BE0] = &bus_be0_clk.common.hw,
[CLK_BUS_BE1] = &bus_be1_clk.common.hw,
[CLK_BUS_BE2] = &bus_be2_clk.common.hw,
[CLK_BUS_DRC0] = &bus_drc0_clk.common.hw,
[CLK_BUS_DRC1] = &bus_drc1_clk.common.hw,
[CLK_FE0_DIV] = &fe0_div_clk.common.hw,
[CLK_FE1_DIV] = &fe1_div_clk.common.hw,
[CLK_FE2_DIV] = &fe2_div_clk.common.hw,
[CLK_BE0_DIV] = &be0_div_clk.common.hw,
[CLK_BE1_DIV] = &be1_div_clk.common.hw,
[CLK_BE2_DIV] = &be2_div_clk.common.hw,
},
.num = CLK_NUMBER,
};
static struct ccu_reset_map sun9i_a80_de_resets[] = {
[RST_FE0] = { 0x0c, BIT(0) },
[RST_FE1] = { 0x0c, BIT(1) },
[RST_FE2] = { 0x0c, BIT(2) },
[RST_DEU0] = { 0x0c, BIT(4) },
[RST_DEU1] = { 0x0c, BIT(5) },
[RST_BE0] = { 0x0c, BIT(8) },
[RST_BE1] = { 0x0c, BIT(9) },
[RST_BE2] = { 0x0c, BIT(10) },
[RST_DRC0] = { 0x0c, BIT(12) },
[RST_DRC1] = { 0x0c, BIT(13) },
[RST_MERGE] = { 0x0c, BIT(20) },
};
static const struct sunxi_ccu_desc sun9i_a80_de_clk_desc = {
.ccu_clks = sun9i_a80_de_clks,
.num_ccu_clks = ARRAY_SIZE(sun9i_a80_de_clks),
.hw_clks = &sun9i_a80_de_hw_clks,
.resets = sun9i_a80_de_resets,
.num_resets = ARRAY_SIZE(sun9i_a80_de_resets),
};
static int sun9i_a80_de_clk_probe(struct platform_device *pdev)
{
struct resource *res;
struct clk *bus_clk;
struct reset_control *rstc;
void __iomem *reg;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(reg))
return PTR_ERR(reg);
bus_clk = devm_clk_get(&pdev->dev, "bus");
if (IS_ERR(bus_clk)) {
ret = PTR_ERR(bus_clk);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Couldn't get bus clk: %d\n", ret);
return ret;
}
rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(rstc)) {
ret = PTR_ERR(bus_clk);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"Couldn't get reset control: %d\n", ret);
return ret;
}
/* The bus clock needs to be enabled for us to access the registers */
ret = clk_prepare_enable(bus_clk);
if (ret) {
dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret);
return ret;
}
/* The reset control needs to be asserted for the controls to work */
ret = reset_control_deassert(rstc);
if (ret) {
dev_err(&pdev->dev,
"Couldn't deassert reset control: %d\n", ret);
goto err_disable_clk;
}
ret = sunxi_ccu_probe(pdev->dev.of_node, reg,
&sun9i_a80_de_clk_desc);
if (ret)
goto err_assert_reset;
return 0;
err_assert_reset:
reset_control_assert(rstc);
err_disable_clk:
clk_disable_unprepare(bus_clk);
return ret;
}
static const struct of_device_id sun9i_a80_de_clk_ids[] = {
{ .compatible = "allwinner,sun9i-a80-de-clks" },
{ }
};
static struct platform_driver sun9i_a80_de_clk_driver = {
.probe = sun9i_a80_de_clk_probe,
.driver = {
.name = "sun9i-a80-de-clks",
.of_match_table = sun9i_a80_de_clk_ids,
},
};
builtin_platform_driver(sun9i_a80_de_clk_driver);
/*
* Copyright 2016 Chen-Yu Tsai
*
* Chen-Yu Tsai <wens@csie.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_SUN9I_A80_DE_H_
#define _CCU_SUN9I_A80_DE_H_
#include <dt-bindings/clock/sun9i-a80-de.h>
#include <dt-bindings/reset/sun9i-a80-de.h>
/* Intermediary clock dividers are not exported */
#define CLK_FE0_DIV 31
#define CLK_FE1_DIV 32
#define CLK_FE2_DIV 33
#define CLK_BE0_DIV 34
#define CLK_BE1_DIV 35
#define CLK_BE2_DIV 36
#define CLK_NUMBER (CLK_BE2_DIV + 1)
#endif /* _CCU_SUN9I_A80_DE_H_ */
/*
* Copyright (c) 2016 Chen-Yu Tsai. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include "ccu_common.h"
#include "ccu_gate.h"
#include "ccu_reset.h"
#include "ccu-sun9i-a80-usb.h"
static SUNXI_CCU_GATE(bus_hci0_clk, "bus-hci0", "bus-usb", 0x0, BIT(1), 0);
static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M", 0x0, BIT(2), 0);
static SUNXI_CCU_GATE(bus_hci1_clk, "bus-hci1", "bus-usb", 0x0, BIT(3), 0);
static SUNXI_CCU_GATE(bus_hci2_clk, "bus-hci2", "bus-usb", 0x0, BIT(5), 0);
static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc24M", 0x0, BIT(6), 0);
static SUNXI_CCU_GATE(usb0_phy_clk, "usb0-phy", "osc24M", 0x4, BIT(1), 0);
static SUNXI_CCU_GATE(usb1_hsic_clk, "usb1-hsic", "osc24M", 0x4, BIT(2), 0);
static SUNXI_CCU_GATE(usb1_phy_clk, "usb1-phy", "osc24M", 0x4, BIT(3), 0);
static SUNXI_CCU_GATE(usb2_hsic_clk, "usb2-hsic", "osc24M", 0x4, BIT(4), 0);
static SUNXI_CCU_GATE(usb2_phy_clk, "usb2-phy", "osc24M", 0x4, BIT(5), 0);
static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "osc24M", 0x4, BIT(10), 0);
static struct ccu_common *sun9i_a80_usb_clks[] = {
&bus_hci0_clk.common,
&usb_ohci0_clk.common,
&bus_hci1_clk.common,
&bus_hci2_clk.common,
&usb_ohci2_clk.common,
&usb0_phy_clk.common,
&usb1_hsic_clk.common,
&usb1_phy_clk.common,
&usb2_hsic_clk.common,
&usb2_phy_clk.common,
&usb_hsic_clk.common,
};
static struct clk_hw_onecell_data sun9i_a80_usb_hw_clks = {
.hws = {
[CLK_BUS_HCI0] = &bus_hci0_clk.common.hw,
[CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw,
[CLK_BUS_HCI1] = &bus_hci1_clk.common.hw,
[CLK_BUS_HCI2] = &bus_hci2_clk.common.hw,
[CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw,
[CLK_USB0_PHY] = &usb0_phy_clk.common.hw,
[CLK_USB1_HSIC] = &usb1_hsic_clk.common.hw,
[CLK_USB1_PHY] = &usb1_phy_clk.common.hw,
[CLK_USB2_HSIC] = &usb2_hsic_clk.common.hw,
[CLK_USB2_PHY] = &usb2_phy_clk.common.hw,
[CLK_USB_HSIC] = &usb_hsic_clk.common.hw,
},
.num = CLK_NUMBER,
};
static struct ccu_reset_map sun9i_a80_usb_resets[] = {
[RST_USB0_HCI] = { 0x0, BIT(17) },
[RST_USB1_HCI] = { 0x0, BIT(18) },
[RST_USB2_HCI] = { 0x0, BIT(19) },
[RST_USB0_PHY] = { 0x4, BIT(17) },
[RST_USB1_HSIC] = { 0x4, BIT(18) },
[RST_USB1_PHY] = { 0x4, BIT(19) },
[RST_USB2_HSIC] = { 0x4, BIT(20) },
[RST_USB2_PHY] = { 0x4, BIT(21) },
};
static const struct sunxi_ccu_desc sun9i_a80_usb_clk_desc = {
.ccu_clks = sun9i_a80_usb_clks,
.num_ccu_clks = ARRAY_SIZE(sun9i_a80_usb_clks),
.hw_clks = &sun9i_a80_usb_hw_clks,
.resets = sun9i_a80_usb_resets,
.num_resets = ARRAY_SIZE(sun9i_a80_usb_resets),
};
static int sun9i_a80_usb_clk_probe(struct platform_device *pdev)
{
struct resource *res;
struct clk *bus_clk;
void __iomem *reg;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(reg))
return PTR_ERR(reg);
bus_clk = devm_clk_get(&pdev->dev, "bus");
if (IS_ERR(bus_clk)) {
ret = PTR_ERR(bus_clk);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Couldn't get bus clk: %d\n", ret);
return ret;
}
/* The bus clock needs to be enabled for us to access the registers */
ret = clk_prepare_enable(bus_clk);
if (ret) {
dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret);
return ret;
}
ret = sunxi_ccu_probe(pdev->dev.of_node, reg,
&sun9i_a80_usb_clk_desc);
if (ret)
goto err_disable_clk;
return 0;
err_disable_clk:
clk_disable_unprepare(bus_clk);
return ret;
}
static const struct of_device_id sun9i_a80_usb_clk_ids[] = {
{ .compatible = "allwinner,sun9i-a80-usb-clks" },
{ }
};
static struct platform_driver sun9i_a80_usb_clk_driver = {
.probe = sun9i_a80_usb_clk_probe,
.driver = {
.name = "sun9i-a80-usb-clks",
.of_match_table = sun9i_a80_usb_clk_ids,
},
};
builtin_platform_driver(sun9i_a80_usb_clk_driver);
/*
* Copyright 2016 Chen-Yu Tsai
*
* Chen-Yu Tsai <wens@csie.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_SUN9I_A80_USB_H_
#define _CCU_SUN9I_A80_USB_H_
#include <dt-bindings/clock/sun9i-a80-usb.h>
#include <dt-bindings/reset/sun9i-a80-usb.h>
#define CLK_NUMBER (CLK_USB_HSIC + 1)
#endif /* _CCU_SUN9I_A80_USB_H_ */
This diff is collapsed.
/*
* Copyright 2016 Chen-Yu Tsai
*
* Chen-Yu Tsai <wens@csie.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_SUN9I_A80_H_
#define _CCU_SUN9I_A80_H_
#include <dt-bindings/clock/sun9i-a80-ccu.h>
#include <dt-bindings/reset/sun9i-a80-ccu.h>
#define CLK_PLL_C0CPUX 0
#define CLK_PLL_C1CPUX 1
/* pll-audio and pll-periph0 are exported to the PRCM block */
#define CLK_PLL_VE 4
#define CLK_PLL_DDR 5
#define CLK_PLL_VIDEO0 6
#define CLK_PLL_VIDEO1 7
#define CLK_PLL_GPU 8
#define CLK_PLL_DE 9
#define CLK_PLL_ISP 10
#define CLK_PLL_PERIPH1 11
/* The CPUX clocks are exported */
#define CLK_ATB0 14
#define CLK_AXI0 15
#define CLK_ATB1 16
#define CLK_AXI1 17
#define CLK_GTBUS 18
#define CLK_AHB0 19
#define CLK_AHB1 20
#define CLK_AHB2 21
#define CLK_APB0 22
#define CLK_APB1 23
#define CLK_CCI400 24
#define CLK_ATS 25
#define CLK_TRACE 26
/* module clocks and bus gates exported */
#define CLK_NUMBER (CLK_BUS_UART5 + 1)
#endif /* _CCU_SUN9I_A80_H_ */
......@@ -25,13 +25,18 @@ static DEFINE_SPINLOCK(ccu_lock);
void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
{
void __iomem *addr;
u32 reg;
if (!lock)
return;
WARN_ON(readl_relaxed_poll_timeout(common->base + common->reg, reg,
reg & lock, 100, 70000));
if (common->features & CCU_FEATURE_LOCK_REG)
addr = common->base + common->lock_reg;
else
addr = common->base + common->reg;
WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000));
}
int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
......
......@@ -21,6 +21,8 @@
#define CCU_FEATURE_VARIABLE_PREDIV BIT(1)
#define CCU_FEATURE_FIXED_PREDIV BIT(2)
#define CCU_FEATURE_FIXED_POSTDIV BIT(3)
#define CCU_FEATURE_ALL_PREDIV BIT(4)
#define CCU_FEATURE_LOCK_REG BIT(5)
struct device_node;
......@@ -56,6 +58,8 @@ struct device_node;
struct ccu_common {
void __iomem *base;
u16 reg;
u16 lock_reg;
u32 prediv;
unsigned long features;
spinlock_t *lock;
......
......@@ -77,6 +77,18 @@ static int ccu_div_determine_rate(struct clk_hw *hw,
{
struct ccu_div *cd = hw_to_ccu_div(hw);
if (clk_hw_get_num_parents(hw) == 1) {
req->rate = divider_round_rate(hw, req->rate,
&req->best_parent_rate,
cd->div.table,
cd->div.width,
cd->div.flags);
req->best_parent_hw = clk_hw_get_parent(hw);
return 0;
}
return ccu_mux_helper_determine_rate(&cd->common, &cd->mux,
req, ccu_div_round_rate, cd);
}
......
......@@ -41,6 +41,7 @@ struct ccu_div_internal {
u8 width;
u32 max;
u32 offset;
u32 flags;
......@@ -58,20 +59,27 @@ struct ccu_div_internal {
#define _SUNXI_CCU_DIV_TABLE(_shift, _width, _table) \
_SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, 0)
#define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags) \
#define _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _off, _max, _flags) \
{ \
.shift = _shift, \
.width = _width, \
.flags = _flags, \
.max = _max, \
.offset = _off, \
}
#define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags) \
_SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, 1, _max, _flags)
#define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags) \
_SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, 0, _flags)
#define _SUNXI_CCU_DIV_MAX(_shift, _width, _max) \
_SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, 0)
#define _SUNXI_CCU_DIV_OFFSET(_shift, _width, _offset) \
_SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _offset, 0, 0)
#define _SUNXI_CCU_DIV(_shift, _width) \
_SUNXI_CCU_DIV_FLAGS(_shift, _width, 0)
......
......@@ -89,11 +89,14 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
m = reg >> cmp->m.shift;
m &= (1 << cmp->m.width) - 1;
m += cmp->m.offset;
if (!m)
m++;
p = reg >> cmp->p.shift;
p &= (1 << cmp->p.width) - 1;
return (parent_rate >> p) / (m + 1);
return (parent_rate >> p) / m;
}
static int ccu_mp_determine_rate(struct clk_hw *hw,
......@@ -124,9 +127,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
reg = readl(cmp->common.base + cmp->common.reg);
reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
reg &= ~GENMASK(cmp->p.width + cmp->p.shift - 1, cmp->p.shift);
reg |= (m - cmp->m.offset) << cmp->m.shift;
reg |= ilog2(p) << cmp->p.shift;
writel(reg | (ilog2(p) << cmp->p.shift) | ((m - 1) << cmp->m.shift),
cmp->common.base + cmp->common.reg);
writel(reg, cmp->common.base + cmp->common.reg);
spin_unlock_irqrestore(cmp->common.lock, flags);
......
......@@ -40,8 +40,13 @@ static unsigned long ccu_mult_round_rate(struct ccu_mux_internal *mux,
struct ccu_mult *cm = data;
struct _ccu_mult _cm;
_cm.min = 1;
_cm.max = 1 << cm->mult.width;
_cm.min = cm->mult.min;
if (cm->mult.max)
_cm.max = cm->mult.max;
else
_cm.max = (1 << cm->mult.width) + cm->mult.offset - 1;
ccu_mult_find_best(parent_rate, rate, &_cm);
return parent_rate * _cm.mult;
......@@ -75,6 +80,9 @@ static unsigned long ccu_mult_recalc_rate(struct clk_hw *hw,
unsigned long val;
u32 reg;
if (ccu_frac_helper_is_enabled(&cm->common, &cm->frac))
return ccu_frac_helper_read_rate(&cm->common, &cm->frac);
reg = readl(cm->common.base + cm->common.reg);
val = reg >> cm->mult.shift;
val &= (1 << cm->mult.width) - 1;
......@@ -82,7 +90,7 @@ static unsigned long ccu_mult_recalc_rate(struct clk_hw *hw,
ccu_mux_helper_adjust_parent_for_prediv(&cm->common, &cm->mux, -1,
&parent_rate);
return parent_rate * (val + 1);
return parent_rate * (val + cm->mult.offset);
}
static int ccu_mult_determine_rate(struct clk_hw *hw,
......@@ -102,20 +110,30 @@ static int ccu_mult_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long flags;
u32 reg;
if (ccu_frac_helper_has_rate(&cm->common, &cm->frac, rate))
return ccu_frac_helper_set_rate(&cm->common, &cm->frac, rate);
else
ccu_frac_helper_disable(&cm->common, &cm->frac);
ccu_mux_helper_adjust_parent_for_prediv(&cm->common, &cm->mux, -1,
&parent_rate);
_cm.min = cm->mult.min;
_cm.max = 1 << cm->mult.width;
if (cm->mult.max)
_cm.max = cm->mult.max;
else
_cm.max = (1 << cm->mult.width) + cm->mult.offset - 1;
ccu_mult_find_best(parent_rate, rate, &_cm);
spin_lock_irqsave(cm->common.lock, flags);
reg = readl(cm->common.base + cm->common.reg);
reg &= ~GENMASK(cm->mult.width + cm->mult.shift - 1, cm->mult.shift);
reg |= ((_cm.mult - cm->mult.offset) << cm->mult.shift);
writel(reg | ((_cm.mult - 1) << cm->mult.shift),
cm->common.base + cm->common.reg);
writel(reg, cm->common.base + cm->common.reg);
spin_unlock_irqrestore(cm->common.lock, flags);
......
......@@ -2,27 +2,39 @@
#define _CCU_MULT_H_
#include "ccu_common.h"
#include "ccu_frac.h"
#include "ccu_mux.h"
struct ccu_mult_internal {
u8 offset;
u8 shift;
u8 width;
u8 min;
u8 max;
};
#define _SUNXI_CCU_MULT_MIN(_shift, _width, _min) \
{ \
.shift = _shift, \
.width = _width, \
.min = _min, \
#define _SUNXI_CCU_MULT_OFFSET_MIN_MAX(_shift, _width, _offset, _min, _max) \
{ \
.min = _min, \
.max = _max, \
.offset = _offset, \
.shift = _shift, \
.width = _width, \
}
#define _SUNXI_CCU_MULT_MIN(_shift, _width, _min) \
_SUNXI_CCU_MULT_OFFSET_MIN_MAX(_shift, _width, 1, _min, 0)
#define _SUNXI_CCU_MULT_OFFSET(_shift, _width, _offset) \
_SUNXI_CCU_MULT_OFFSET_MIN_MAX(_shift, _width, _offset, 1, 0)
#define _SUNXI_CCU_MULT(_shift, _width) \
_SUNXI_CCU_MULT_MIN(_shift, _width, 1)
_SUNXI_CCU_MULT_OFFSET_MIN_MAX(_shift, _width, 1, 1, 0)
struct ccu_mult {
u32 enable;
struct ccu_frac_internal frac;
struct ccu_mult_internal mult;
struct ccu_mux_internal mux;
struct ccu_common common;
......
......@@ -25,9 +25,15 @@ void ccu_mux_helper_adjust_parent_for_prediv(struct ccu_common *common,
int i;
if (!((common->features & CCU_FEATURE_FIXED_PREDIV) ||
(common->features & CCU_FEATURE_VARIABLE_PREDIV)))
(common->features & CCU_FEATURE_VARIABLE_PREDIV) ||
(common->features & CCU_FEATURE_ALL_PREDIV)))
return;
if (common->features & CCU_FEATURE_ALL_PREDIV) {
*parent_rate = *parent_rate / common->prediv;
return;
}
reg = readl(common->base + common->reg);
if (parent_index < 0) {
parent_index = reg >> cm->shift;
......@@ -64,19 +70,46 @@ int ccu_mux_helper_determine_rate(struct ccu_common *common,
struct clk_hw *best_parent, *hw = &common->hw;
unsigned int i;
if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
unsigned long adj_parent_rate;
best_parent = clk_hw_get_parent(hw);
best_parent_rate = clk_hw_get_rate(best_parent);
adj_parent_rate = best_parent_rate;
ccu_mux_helper_adjust_parent_for_prediv(common, cm, -1,
&adj_parent_rate);
best_rate = round(cm, adj_parent_rate, req->rate, data);
goto out;
}
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
unsigned long tmp_rate, parent_rate;
unsigned long tmp_rate, parent_rate, adj_parent_rate;
struct clk_hw *parent;
parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
parent_rate = clk_hw_get_rate(parent);
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
struct clk_rate_request parent_req = *req;
int ret = __clk_determine_rate(parent, &parent_req);
if (ret)
continue;
parent_rate = parent_req.rate;
} else {
parent_rate = clk_hw_get_rate(parent);
}
adj_parent_rate = parent_rate;
ccu_mux_helper_adjust_parent_for_prediv(common, cm, i,
&parent_rate);
&adj_parent_rate);
tmp_rate = round(cm, clk_hw_get_rate(parent), req->rate, data);
tmp_rate = round(cm, adj_parent_rate, req->rate, data);
if (tmp_rate == req->rate) {
best_parent = parent;
best_parent_rate = parent_rate;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -80,11 +80,17 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
n = reg >> nm->n.shift;
n &= (1 << nm->n.width) - 1;
n += nm->n.offset;
if (!n)
n++;
m = reg >> nm->m.shift;
m &= (1 << nm->m.width) - 1;
m += nm->m.offset;
if (!m)
m++;
return parent_rate * (n + 1) / (m + 1);
return parent_rate * n / m;
}
static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
......@@ -94,7 +100,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
struct _ccu_nm _nm;
_nm.min_n = nm->n.min;
_nm.max_n = 1 << nm->n.width;
_nm.max_n = nm->n.max ?: 1 << nm->n.width;
_nm.min_m = 1;
_nm.max_m = nm->m.max ?: 1 << nm->m.width;
......@@ -117,7 +123,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
ccu_frac_helper_disable(&nm->common, &nm->frac);
_nm.min_n = 1;
_nm.max_n = 1 << nm->n.width;
_nm.max_n = nm->n.max ?: 1 << nm->n.width;
_nm.min_m = 1;
_nm.max_m = nm->m.max ?: 1 << nm->m.width;
......@@ -129,8 +135,9 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
reg &= ~GENMASK(nm->n.width + nm->n.shift - 1, nm->n.shift);
reg &= ~GENMASK(nm->m.width + nm->m.shift - 1, nm->m.shift);
writel(reg | ((_nm.m - 1) << nm->m.shift) | ((_nm.n - 1) << nm->n.shift),
nm->common.base + nm->common.reg);
reg |= (_nm.n - nm->n.offset) << nm->n.shift;
reg |= (_nm.m - nm->m.offset) << nm->m.shift;
writel(reg, nm->common.base + nm->common.reg);
spin_unlock_irqrestore(nm->common.lock, flags);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment