Commit 6d0485a9 authored by Nicolas Ferre's avatar Nicolas Ferre Committed by Russell King
Browse files

[ARM] 5438/1: AT91: manage clock by functionality instead of CPUs



In clock.c file the clock management is grouped by cpu with cpu_is_xxx()
function. This lead to some kind of difficulties to read this file and
maintainability issues as the number of AT91 cpus & PLLs/clocks is growing.

In this patch, I try to group clock functionality together and match cpus with
this functionality set.
An update to at91_pmc.h is needed to cover some new PMC possibilities (and
some update in comments).

Signed-off-by: default avatarNicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: default avatarAndrew Victor <avictor.za@gmail.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent b4175b89
Loading
Loading
Loading
Loading
+112 −39
Original line number Diff line number Diff line
@@ -43,6 +43,25 @@
#define clk_is_sys(x)		((x)->type & CLK_TYPE_SYSTEM)


/*
 * Chips have some kind of clocks : group them by functionality
 */
#define cpu_has_utmi()		(  cpu_is_at91cap9() \
				|| cpu_is_at91sam9rl())

#define cpu_has_800M_plla()	(cpu_is_at91sam9g20())

#define cpu_has_pllb()		(!cpu_is_at91sam9rl())

#define cpu_has_upll()		(0)

/* USB host HS & FS */
#define cpu_has_uhp()		(!cpu_is_at91sam9rl())

/* USB device FS only */
#define cpu_has_udpfs()		(!cpu_is_at91sam9rl())


static LIST_HEAD(clocks);
static DEFINE_SPINLOCK(clk_lock);

@@ -140,7 +159,7 @@ static struct clk utmi_clk = {
};
static struct clk uhpck = {
	.name		= "uhpck",
	.parent		= &pllb,
	/*.parent		= ... we choose parent at runtime */
	.mode		= pmc_sys_mode,
};

@@ -173,6 +192,10 @@ static struct clk __init *at91_css_to_clk(unsigned long css)
		case AT91_PMC_CSS_PLLA:
			return &plla;
		case AT91_PMC_CSS_PLLB:
			if (cpu_has_upll())
				/* CSS_PLLB == CSS_UPLL */
				return &utmi_clk;
			else if (cpu_has_pllb())
				return &pllb;
	}

@@ -322,7 +345,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
			u32	pckr;

			pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
			pckr &= AT91_PMC_CSS_PLLB;	/* clock selection */
			pckr &= AT91_PMC_CSS;	/* clock selection */
			pckr |= prescale << 2;
			at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
			clk->rate_hz = actual;
@@ -361,7 +384,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
}
EXPORT_SYMBOL(clk_set_parent);

/* establish PCK0..PCK3 parentage and rate */
/* establish PCK0..PCKN parentage and rate */
static void __init init_programmable_clock(struct clk *clk)
{
	struct clk	*parent;
@@ -389,11 +412,13 @@ static int at91_clk_show(struct seq_file *s, void *unused)
	seq_printf(s, "MOR  = %8x\n", at91_sys_read(AT91_CKGR_MOR));
	seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR));
	seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR));
	if (!cpu_is_at91sam9rl())
	if (cpu_has_pllb())
		seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR));
	if (cpu_is_at91cap9() || cpu_is_at91sam9rl())
	if (cpu_has_utmi())
		seq_printf(s, "UCKR = %8x\n", uckr = at91_sys_read(AT91_CKGR_UCKR));
	seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR));
	if (cpu_has_upll())
		seq_printf(s, "USB  = %8x\n", at91_sys_read(AT91_PMC_USB));
	seq_printf(s, "SR   = %8x\n", sr = at91_sys_read(AT91_PMC_SR));

	seq_printf(s, "\n");
@@ -554,16 +579,60 @@ static struct clk *const standard_pmc_clocks[] __initdata = {
	&clk32k,
	&main_clk,
	&plla,
	&pllb,

	/* PLLB children (USB) */
	&udpck,
	&uhpck,

	/* MCK */
	&mck
};

/* PLLB generated USB full speed clock init */
static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock)
{
	/*
	 * USB clock init:  choose 48 MHz PLLB value,
	 * disable 48MHz clock during usb peripheral suspend.
	 *
	 * REVISIT:  assumes MCK doesn't derive from PLLB!
	 */
	uhpck.parent = &pllb;

	at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M;
	pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init);
	if (cpu_is_at91rm9200()) {
		uhpck.pmc_mask = AT91RM9200_PMC_UHP;
		udpck.pmc_mask = AT91RM9200_PMC_UDP;
		at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
		uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
		udpck.pmc_mask = AT91SAM926x_PMC_UDP;
	} else if (cpu_is_at91cap9()) {
		uhpck.pmc_mask = AT91CAP9_PMC_UHP;
	}
	at91_sys_write(AT91_CKGR_PLLBR, 0);

	udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
	uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
}

/* UPLL generated USB full speed clock init */
static void __init at91_upll_usbfs_clock_init(unsigned long main_clock)
{
	/*
	 * USB clock init: choose 480 MHz from UPLL,
	 */
	unsigned int usbr = AT91_PMC_USBS_UPLL;

	/* Setup divider by 10 to reach 48 MHz */
	usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV;

	at91_sys_write(AT91_PMC_USB, usbr);

	/* Now set uhpck values */
	uhpck.parent = &utmi_clk;
	uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
	uhpck.rate_hz = utmi_clk.parent->rate_hz;
	uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
}

int __init at91_clock_init(unsigned long main_clock)
{
	unsigned tmp, freq, mckr;
@@ -585,43 +654,37 @@ int __init at91_clock_init(unsigned long main_clock)

	/* report if PLLA is more than mildly overclocked */
	plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR));
	if ((!cpu_is_at91sam9g20() && plla.rate_hz > 209000000)
	   || (cpu_is_at91sam9g20() && plla.rate_hz > 800000000))
	if ((!cpu_has_800M_plla() && plla.rate_hz > 209000000)
	   || (cpu_has_800M_plla() && plla.rate_hz > 800000000))
		pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);

	/*
	 * USB clock init:  choose 48 MHz PLLB value,
	 * disable 48MHz clock during usb peripheral suspend.
	 *
	 * REVISIT:  assumes MCK doesn't derive from PLLB!
	 */
	at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M;
	pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init);
	if (cpu_is_at91rm9200()) {
		uhpck.pmc_mask = AT91RM9200_PMC_UHP;
		udpck.pmc_mask = AT91RM9200_PMC_UDP;
		at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
		uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
		udpck.pmc_mask = AT91SAM926x_PMC_UDP;
	} else if (cpu_is_at91cap9()) {
		uhpck.pmc_mask = AT91CAP9_PMC_UHP;

	if (cpu_has_upll() && !cpu_has_pllb()) {
		/* setup UTMI clock as the fourth primary clock
		 * (instead of pllb) */
		utmi_clk.type |= CLK_TYPE_PRIMARY;
		utmi_clk.id = 3;
	}
	at91_sys_write(AT91_CKGR_PLLBR, 0);

	udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
	uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);

	/*
	 * USB HS clock init
	 */
	if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) {
	if (cpu_has_utmi())
		/*
		 * multiplier is hard-wired to 40
		 * (obtain the USB High Speed 480 MHz when input is 12 MHz)
		 */
		utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
	}

	/*
	 * USB FS clock init
	 */
	if (cpu_has_pllb())
		at91_pllb_usbfs_clock_init(main_clock);
	if (cpu_has_upll())
		/* assumes that we choose UPLL for USB and not PLLA */
		at91_upll_usbfs_clock_init(main_clock);

	/*
	 * MCK and CPU derive from one of those primary clocks.
@@ -631,21 +694,31 @@ int __init at91_clock_init(unsigned long main_clock)
	mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
	freq = mck.parent->rate_hz;
	freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2));				/* prescale */
	if (cpu_is_at91rm9200())
	if (cpu_is_at91rm9200()) {
		mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8));	/* mdiv */
	else if (cpu_is_at91sam9g20()) {
	} else if (cpu_is_at91sam9g20()) {
		mck.rate_hz = (mckr & AT91_PMC_MDIV) ?
			freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq;	/* mdiv ; (x >> 7) = ((x >> 8) * 2) */
		if (mckr & AT91_PMC_PDIV)
			freq /= 2;		/* processor clock division */
	} else
	} else {
		mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));      /* mdiv */
	}

	/* Register the PMC's standard clocks */
	for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
		list_add_tail(&standard_pmc_clocks[i]->node, &clocks);

	if (cpu_is_at91cap9() || cpu_is_at91sam9rl())
	if (cpu_has_pllb())
		list_add_tail(&pllb.node, &clocks);

	if (cpu_has_uhp())
		list_add_tail(&uhpck.node, &clocks);

	if (cpu_has_udpfs())
		list_add_tail(&udpck.node, &clocks);

	if (cpu_has_utmi())
		list_add_tail(&utmi_clk.node, &clocks);

	/* MCK and CPU clock are "always on" */
+20 −6
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@
#define		AT91_PMC_PCK		(1 <<  0)		/* Processor Clock */
#define		AT91RM9200_PMC_UDP	(1 <<  1)		/* USB Devcice Port Clock [AT91RM9200 only] */
#define		AT91RM9200_PMC_MCKUDP	(1 <<  2)		/* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
#define		AT91CAP9_PMC_DDR	(1 <<  2)		/* DDR Clock [AT91CAP9 revC only] */
#define		AT91CAP9_PMC_DDR	(1 <<  2)		/* DDR Clock [CAP9 revC & some SAM9 only] */
#define		AT91RM9200_PMC_UHP	(1 <<  4)		/* USB Host Port Clock [AT91RM9200 only] */
#define		AT91SAM926x_PMC_UHP	(1 <<  6)		/* USB Host Port Clock [AT91SAM926x only] */
#define		AT91CAP9_PMC_UHP	(1 <<  6)		/* USB Host Port Clock [AT91CAP9 only] */
@@ -39,11 +39,11 @@
#define	AT91_PMC_PCDR		(AT91_PMC + 0x14)	/* Peripheral Clock Disable Register */
#define	AT91_PMC_PCSR		(AT91_PMC + 0x18)	/* Peripheral Clock Status Register */

#define	AT91_CKGR_UCKR		(AT91_PMC + 0x1C)	/* UTMI Clock Register [SAM9RL, CAP9] */
#define	AT91_CKGR_UCKR		(AT91_PMC + 0x1C)	/* UTMI Clock Register [some SAM9, CAP9] */
#define		AT91_PMC_UPLLEN		(1   << 16)		/* UTMI PLL Enable */
#define		AT91_PMC_UPLLCOUNT	(0xf << 20)		/* UTMI PLL Start-up Time */
#define		AT91_PMC_BIASEN		(1   << 24)		/* UTMI BIAS Enable */
#define		AT91_PMC_BIASCOUNT	(0xf << 28)		/* UTMI PLL Start-up Time */
#define		AT91_PMC_BIASCOUNT	(0xf << 28)		/* UTMI BIAS Start-up Time */

#define	AT91_CKGR_MOR		(AT91_PMC + 0x20)	/* Main Oscillator Register [not on SAM9RL] */
#define		AT91_PMC_MOSCEN		(1    << 0)		/* Main Oscillator Enable */
@@ -72,6 +72,7 @@
#define			AT91_PMC_CSS_MAIN		(1 << 0)
#define			AT91_PMC_CSS_PLLA		(2 << 0)
#define			AT91_PMC_CSS_PLLB		(3 << 0)
#define			AT91_PMC_CSS_UPLL		(3 << 0)	/* [some SAM9 only] */
#define		AT91_PMC_PRES		(7 <<  2)		/* Master Clock Prescaler */
#define			AT91_PMC_PRES_1			(0 << 2)
#define			AT91_PMC_PRES_2			(1 << 2)
@@ -88,12 +89,25 @@
#define			AT91SAM9_PMC_MDIV_1		(0 << 8)	/* [SAM9,CAP9 only] */
#define			AT91SAM9_PMC_MDIV_2		(1 << 8)
#define			AT91SAM9_PMC_MDIV_4		(2 << 8)
#define			AT91SAM9_PMC_MDIV_6		(3 << 8)
#define			AT91SAM9_PMC_MDIV_6		(3 << 8)	/* [some SAM9 only] */
#define			AT91SAM9_PMC_MDIV_3		(3 << 8)	/* [some SAM9 only] */
#define		AT91_PMC_PDIV		(1 << 12)		/* Processor Clock Division [some SAM9 only] */
#define			AT91_PMC_PDIV_1			(0 << 12)
#define			AT91_PMC_PDIV_2			(1 << 12)
#define		AT91_PMC_PLLADIV2	(1 << 12)		/* PLLA divisor by 2 [some SAM9 only] */
#define			AT91_PMC_PLLADIV2_OFF		(0 << 12)
#define			AT91_PMC_PLLADIV2_ON		(1 << 12)

#define	AT91_PMC_PCKR(n)	(AT91_PMC + 0x40 + ((n) * 4))	/* Programmable Clock 0-3 Registers */
#define	AT91_PMC_USB		(AT91_PMC + 0x38)	/* USB Clock Register [some SAM9 only] */
#define		AT91_PMC_USBS		(0x1 <<  0)		/* USB OHCI Input clock selection */
#define			AT91_PMC_USBS_PLLA		(0 << 0)
#define			AT91_PMC_USBS_UPLL		(1 << 0)
#define		AT91_PMC_OHCIUSBDIV	(0xF <<  8)		/* Divider for USB OHCI Clock */

#define	AT91_PMC_PCKR(n)	(AT91_PMC + 0x40 + ((n) * 4))	/* Programmable Clock 0-N Registers */
#define		AT91_PMC_CSSMCK		(0x1 <<  8)		/* CSS or Master Clock Selection */
#define			AT91_PMC_CSSMCK_CSS		(0 << 8)
#define			AT91_PMC_CSSMCK_MCK		(1 << 8)

#define	AT91_PMC_IER		(AT91_PMC + 0x60)	/* Interrupt Enable Register */
#define	AT91_PMC_IDR		(AT91_PMC + 0x64)	/* Interrupt Disable Register */
@@ -102,7 +116,7 @@
#define		AT91_PMC_LOCKA		(1 <<  1)		/* PLLA Lock */
#define		AT91_PMC_LOCKB		(1 <<  2)		/* PLLB Lock */
#define		AT91_PMC_MCKRDY		(1 <<  3)		/* Master Clock */
#define		AT91_PMC_LOCKU		(1 <<  6)		/* UPLL Lock [AT91CAP9 only] */
#define		AT91_PMC_LOCKU		(1 <<  6)		/* UPLL Lock [some SAM9, AT91CAP9 only] */
#define		AT91_PMC_OSCSEL		(1 <<  7)		/* Slow Clock Oscillator [AT91CAP9 revC only] */
#define		AT91_PMC_PCK0RDY	(1 <<  8)		/* Programmable Clock 0 */
#define		AT91_PMC_PCK1RDY	(1 <<  9)		/* Programmable Clock 1 */