xref: /kernel/linux/linux-6.6/arch/powerpc/boot/pq2.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PowerQUICC II support functions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Scott Wood <scottwood@freescale.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2007 Freescale Semiconductor, Inc.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "ops.h"
1162306a36Sopenharmony_ci#include "types.h"
1262306a36Sopenharmony_ci#include "fsl-soc.h"
1362306a36Sopenharmony_ci#include "pq2.h"
1462306a36Sopenharmony_ci#include "stdio.h"
1562306a36Sopenharmony_ci#include "io.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define PQ2_SCCR (0x10c80/4) /* System Clock Configuration Register */
1862306a36Sopenharmony_ci#define PQ2_SCMR (0x10c88/4) /* System Clock Mode Register */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic int pq2_corecnf_map[] = {
2162306a36Sopenharmony_ci	3, 2, 2, 2, 4, 4, 5, 9, 6, 11, 8, 10, 3, 12, 7, -1,
2262306a36Sopenharmony_ci	6, 5, 13, 2, 14, 4, 15, 9, 0, 11, 8, 10, 16, 12, 7, -1
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Get various clocks from crystal frequency.
2662306a36Sopenharmony_ci * Returns zero on failure and non-zero on success.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ciint pq2_get_clocks(u32 crystal, u32 *sysfreq, u32 *corefreq,
2962306a36Sopenharmony_ci                   u32 *timebase, u32 *brgfreq)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	u32 *immr;
3262306a36Sopenharmony_ci	u32 sccr, scmr, mainclk, busclk;
3362306a36Sopenharmony_ci	int corecnf, busdf, plldf, pllmf, dfbrg;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	immr = fsl_get_immr();
3662306a36Sopenharmony_ci	if (!immr) {
3762306a36Sopenharmony_ci		printf("pq2_get_clocks: Couldn't get IMMR base.\r\n");
3862306a36Sopenharmony_ci		return 0;
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	sccr = in_be32(&immr[PQ2_SCCR]);
4262306a36Sopenharmony_ci	scmr = in_be32(&immr[PQ2_SCMR]);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	dfbrg = sccr & 3;
4562306a36Sopenharmony_ci	corecnf = (scmr >> 24) & 0x1f;
4662306a36Sopenharmony_ci	busdf = (scmr >> 20) & 0xf;
4762306a36Sopenharmony_ci	plldf = (scmr >> 12) & 1;
4862306a36Sopenharmony_ci	pllmf = scmr & 0xfff;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	mainclk = crystal * (pllmf + 1) / (plldf + 1);
5162306a36Sopenharmony_ci	busclk = mainclk / (busdf + 1);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (sysfreq)
5462306a36Sopenharmony_ci		*sysfreq = mainclk / 2;
5562306a36Sopenharmony_ci	if (timebase)
5662306a36Sopenharmony_ci		*timebase = busclk / 4;
5762306a36Sopenharmony_ci	if (brgfreq)
5862306a36Sopenharmony_ci		*brgfreq = mainclk / (1 << ((dfbrg + 1) * 2));
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (corefreq) {
6162306a36Sopenharmony_ci		int coremult = pq2_corecnf_map[corecnf];
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		if (coremult < 0)
6462306a36Sopenharmony_ci			*corefreq = mainclk / 2;
6562306a36Sopenharmony_ci		else if (coremult == 0)
6662306a36Sopenharmony_ci			return 0;
6762306a36Sopenharmony_ci		else
6862306a36Sopenharmony_ci			*corefreq = busclk * coremult / 2;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return 1;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/* Set common device tree fields based on the given clock frequencies. */
7562306a36Sopenharmony_civoid pq2_set_clocks(u32 sysfreq, u32 corefreq, u32 timebase, u32 brgfreq)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	void *node;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	dt_fixup_cpu_clocks(corefreq, timebase, sysfreq);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	node = finddevice("/soc/cpm");
8262306a36Sopenharmony_ci	if (node)
8362306a36Sopenharmony_ci		setprop(node, "clock-frequency", &sysfreq, 4);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	node = finddevice("/soc/cpm/brg");
8662306a36Sopenharmony_ci	if (node)
8762306a36Sopenharmony_ci		setprop(node, "clock-frequency", &brgfreq, 4);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ciint pq2_fixup_clocks(u32 crystal)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	u32 sysfreq, corefreq, timebase, brgfreq;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (!pq2_get_clocks(crystal, &sysfreq, &corefreq, &timebase, &brgfreq))
9562306a36Sopenharmony_ci		return 0;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	pq2_set_clocks(sysfreq, corefreq, timebase, brgfreq);
9862306a36Sopenharmony_ci	return 1;
9962306a36Sopenharmony_ci}
100