Commit b9df3997 authored by Zhou Yanjie's avatar Zhou Yanjie Committed by Stephen Boyd
Browse files

clk: Ingenic: Add CGU driver for X1000.



Add support for the clocks provided by the CGU in the Ingenic X1000
SoC, making use of the cgu code to do the heavy lifting.

Signed-off-by: default avatarZhou Yanjie <zhouyanjie@zoho.com>
Link: https://lkml.kernel.org/r/1573378102-72380-3-git-send-email-zhouyanjie@zoho.com


Reviewed-by: default avatarPaul Cercueil <paul@crapouillou.net>
Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent 0b24748c
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -45,6 +45,16 @@ config INGENIC_CGU_JZ4780

	  If building for a JZ4780 SoC, you want to say Y here.

config INGENIC_CGU_X1000
	bool "Ingenic X1000 CGU driver"
	default MACH_X1000
	select INGENIC_CGU_COMMON
	help
	  Support the clocks provided by the CGU hardware on Ingenic X1000
	  and compatible SoCs.

	  If building for a X1000 SoC, you want to say Y here.

config INGENIC_TCU_CLK
	bool "Ingenic JZ47xx TCU clocks driver"
	default MACH_INGENIC
+1 −0
Original line number Diff line number Diff line
@@ -4,4 +4,5 @@ obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4725B)	+= jz4725b-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4770)	+= jz4770-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4780)	+= jz4780-cgu.o
obj-$(CONFIG_INGENIC_CGU_X1000)		+= x1000-cgu.o
obj-$(CONFIG_INGENIC_TCU_CLK)		+= tcu.o
+274 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * X1000 SoC CGU driver
 * Copyright (c) 2019 Zhou Yanjie <zhouyanjie@zoho.com>
 */

#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <dt-bindings/clock/x1000-cgu.h>
#include "cgu.h"
#include "pm.h"

/* CGU register offsets */
#define CGU_REG_CPCCR		0x00
#define CGU_REG_APLL		0x10
#define CGU_REG_MPLL		0x14
#define CGU_REG_CLKGR		0x20
#define CGU_REG_OPCR		0x24
#define CGU_REG_DDRCDR		0x2c
#define CGU_REG_MACCDR		0x54
#define CGU_REG_I2SCDR		0x60
#define CGU_REG_LPCDR		0x64
#define CGU_REG_MSC0CDR		0x68
#define CGU_REG_I2SCDR1		0x70
#define CGU_REG_SSICDR		0x74
#define CGU_REG_CIMCDR		0x7c
#define CGU_REG_PCMCDR		0x84
#define CGU_REG_MSC1CDR		0xa4
#define CGU_REG_CMP_INTR	0xb0
#define CGU_REG_CMP_INTRE	0xb4
#define CGU_REG_DRCG		0xd0
#define CGU_REG_CPCSR		0xd4
#define CGU_REG_PCMCDR1		0xe0
#define CGU_REG_MACPHYC		0xe8

/* bits within the OPCR register */
#define OPCR_SPENDN0		BIT(7)
#define OPCR_SPENDN1		BIT(6)

static struct ingenic_cgu *cgu;

static const s8 pll_od_encoding[8] = {
	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
};

static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {

	/* External clocks */

	[X1000_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
	[X1000_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },

	/* PLLs */

	[X1000_CLK_APLL] = {
		"apll", CGU_CLK_PLL,
		.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
		.pll = {
			.reg = CGU_REG_APLL,
			.m_shift = 24,
			.m_bits = 7,
			.m_offset = 1,
			.n_shift = 18,
			.n_bits = 5,
			.n_offset = 1,
			.od_shift = 16,
			.od_bits = 2,
			.od_max = 8,
			.od_encoding = pll_od_encoding,
			.bypass_bit = 9,
			.enable_bit = 8,
			.stable_bit = 10,
		},
	},

	[X1000_CLK_MPLL] = {
		"mpll", CGU_CLK_PLL,
		.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
		.pll = {
			.reg = CGU_REG_MPLL,
			.m_shift = 24,
			.m_bits = 7,
			.m_offset = 1,
			.n_shift = 18,
			.n_bits = 5,
			.n_offset = 1,
			.od_shift = 16,
			.od_bits = 2,
			.od_max = 8,
			.od_encoding = pll_od_encoding,
			.bypass_bit = 6,
			.enable_bit = 7,
			.stable_bit = 0,
		},
	},

	/* Muxes & dividers */

	[X1000_CLK_SCLKA] = {
		"sclk_a", CGU_CLK_MUX,
		.parents = { -1, X1000_CLK_EXCLK, X1000_CLK_APLL, -1 },
		.mux = { CGU_REG_CPCCR, 30, 2 },
	},

	[X1000_CLK_CPUMUX] = {
		"cpu_mux", CGU_CLK_MUX,
		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
		.mux = { CGU_REG_CPCCR, 28, 2 },
	},

	[X1000_CLK_CPU] = {
		"cpu", CGU_CLK_DIV,
		.parents = { X1000_CLK_CPUMUX, -1, -1, -1 },
		.div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
	},

	[X1000_CLK_L2CACHE] = {
		"l2cache", CGU_CLK_DIV,
		.parents = { X1000_CLK_CPUMUX, -1, -1, -1 },
		.div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
	},

	[X1000_CLK_AHB0] = {
		"ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
		.mux = { CGU_REG_CPCCR, 26, 2 },
		.div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 },
	},

	[X1000_CLK_AHB2PMUX] = {
		"ahb2_apb_mux", CGU_CLK_MUX,
		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
		.mux = { CGU_REG_CPCCR, 24, 2 },
	},

	[X1000_CLK_AHB2] = {
		"ahb2", CGU_CLK_DIV,
		.parents = { X1000_CLK_AHB2PMUX, -1, -1, -1 },
		.div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 },
	},

	[X1000_CLK_PCLK] = {
		"pclk", CGU_CLK_DIV,
		.parents = { X1000_CLK_AHB2PMUX, -1, -1, -1 },
		.div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 },
	},

	[X1000_CLK_DDR] = {
		"ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
		.mux = { CGU_REG_DDRCDR, 30, 2 },
		.div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 },
		.gate = { CGU_REG_CLKGR, 31 },
	},

	[X1000_CLK_MAC] = {
		"mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL},
		.mux = { CGU_REG_MACCDR, 31, 1 },
		.div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 },
		.gate = { CGU_REG_CLKGR, 25 },
	},

	[X1000_CLK_MSCMUX] = {
		"msc_mux", CGU_CLK_MUX,
		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL},
		.mux = { CGU_REG_MSC0CDR, 31, 1 },
	},

	[X1000_CLK_MSC0] = {
		"msc0", CGU_CLK_DIV | CGU_CLK_GATE,
		.parents = { X1000_CLK_MSCMUX, -1, -1, -1 },
		.div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 },
		.gate = { CGU_REG_CLKGR, 4 },
	},

	[X1000_CLK_MSC1] = {
		"msc1", CGU_CLK_DIV | CGU_CLK_GATE,
		.parents = { X1000_CLK_MSCMUX, -1, -1, -1 },
		.div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 },
		.gate = { CGU_REG_CLKGR, 5 },
	},

	[X1000_CLK_SSIPLL] = {
		"ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL, -1, -1 },
		.mux = { CGU_REG_SSICDR, 31, 1 },
		.div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 },
	},

	[X1000_CLK_SSIMUX] = {
		"ssi_mux", CGU_CLK_MUX,
		.parents = { X1000_CLK_EXCLK, X1000_CLK_SSIPLL, -1, -1 },
		.mux = { CGU_REG_SSICDR, 30, 1 },
	},

	/* Gate-only clocks */

	[X1000_CLK_SFC] = {
		"sfc", CGU_CLK_GATE,
		.parents = { X1000_CLK_SSIPLL, -1, -1, -1 },
		.gate = { CGU_REG_CLKGR, 2 },
	},

	[X1000_CLK_I2C0] = {
		"i2c0", CGU_CLK_GATE,
		.parents = { X1000_CLK_PCLK, -1, -1, -1 },
		.gate = { CGU_REG_CLKGR, 7 },
	},

	[X1000_CLK_I2C1] = {
		"i2c1", CGU_CLK_GATE,
		.parents = { X1000_CLK_PCLK, -1, -1, -1 },
		.gate = { CGU_REG_CLKGR, 8 },
	},

	[X1000_CLK_I2C2] = {
		"i2c2", CGU_CLK_GATE,
		.parents = { X1000_CLK_PCLK, -1, -1, -1 },
		.gate = { CGU_REG_CLKGR, 9 },
	},

	[X1000_CLK_UART0] = {
		"uart0", CGU_CLK_GATE,
		.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
		.gate = { CGU_REG_CLKGR, 14 },
	},

	[X1000_CLK_UART1] = {
		"uart1", CGU_CLK_GATE,
		.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
		.gate = { CGU_REG_CLKGR, 15 },
	},

	[X1000_CLK_UART2] = {
		"uart2", CGU_CLK_GATE,
		.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
		.gate = { CGU_REG_CLKGR, 16 },
	},

	[X1000_CLK_SSI] = {
		"ssi", CGU_CLK_GATE,
		.parents = { X1000_CLK_SSIMUX, -1, -1, -1 },
		.gate = { CGU_REG_CLKGR, 19 },
	},

	[X1000_CLK_PDMA] = {
		"pdma", CGU_CLK_GATE,
		.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
		.gate = { CGU_REG_CLKGR, 21 },
	},
};

static void __init x1000_cgu_init(struct device_node *np)
{
	int retval;

	cgu = ingenic_cgu_new(x1000_cgu_clocks,
			      ARRAY_SIZE(x1000_cgu_clocks), np);
	if (!cgu) {
		pr_err("%s: failed to initialise CGU\n", __func__);
		return;
	}

	retval = ingenic_cgu_register_clocks(cgu);
	if (retval) {
		pr_err("%s: failed to register CGU Clocks\n", __func__);
		return;
	}

	ingenic_cgu_register_syscore_ops(cgu);
}
CLK_OF_DECLARE(x1000_cgu, "ingenic,x1000-cgu", x1000_cgu_init);