18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * MPC8xx support functions
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Scott Wood <scottwood@freescale.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2007 Freescale Semiconductor, Inc.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "ops.h"
118c2ecf20Sopenharmony_ci#include "types.h"
128c2ecf20Sopenharmony_ci#include "fsl-soc.h"
138c2ecf20Sopenharmony_ci#include "mpc8xx.h"
148c2ecf20Sopenharmony_ci#include "stdio.h"
158c2ecf20Sopenharmony_ci#include "io.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define MPC8XX_PLPRCR (0x284/4) /* PLL and Reset Control Register */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* Return system clock from crystal frequency */
208c2ecf20Sopenharmony_ciu32 mpc885_get_clock(u32 crystal)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	u32 *immr;
238c2ecf20Sopenharmony_ci	u32 plprcr;
248c2ecf20Sopenharmony_ci	int mfi, mfn, mfd, pdf;
258c2ecf20Sopenharmony_ci	u32 ret;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	immr = fsl_get_immr();
288c2ecf20Sopenharmony_ci	if (!immr) {
298c2ecf20Sopenharmony_ci		printf("mpc885_get_clock: Couldn't get IMMR base.\r\n");
308c2ecf20Sopenharmony_ci		return 0;
318c2ecf20Sopenharmony_ci	}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	plprcr = in_be32(&immr[MPC8XX_PLPRCR]);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	mfi = (plprcr >> 16) & 15;
368c2ecf20Sopenharmony_ci	if (mfi < 5) {
378c2ecf20Sopenharmony_ci		printf("Warning: PLPRCR[MFI] value of %d out-of-bounds\r\n",
388c2ecf20Sopenharmony_ci		       mfi);
398c2ecf20Sopenharmony_ci		mfi = 5;
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	pdf = (plprcr >> 1) & 0xf;
438c2ecf20Sopenharmony_ci	mfd = (plprcr >> 22) & 0x1f;
448c2ecf20Sopenharmony_ci	mfn = (plprcr >> 27) & 0x1f;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	ret = crystal * mfi;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (mfn != 0)
498c2ecf20Sopenharmony_ci		ret += crystal * mfn / (mfd + 1);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return ret / (pdf + 1);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* Set common device tree fields based on the given clock frequencies. */
558c2ecf20Sopenharmony_civoid mpc8xx_set_clocks(u32 sysclk)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	void *node;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	dt_fixup_cpu_clocks(sysclk, sysclk / 16, sysclk);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	node = finddevice("/soc/cpm");
628c2ecf20Sopenharmony_ci	if (node)
638c2ecf20Sopenharmony_ci		setprop(node, "clock-frequency", &sysclk, 4);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	node = finddevice("/soc/cpm/brg");
668c2ecf20Sopenharmony_ci	if (node)
678c2ecf20Sopenharmony_ci		setprop(node, "clock-frequency", &sysclk, 4);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciint mpc885_fixup_clocks(u32 crystal)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	u32 sysclk = mpc885_get_clock(crystal);
738c2ecf20Sopenharmony_ci	if (!sysclk)
748c2ecf20Sopenharmony_ci		return 0;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	mpc8xx_set_clocks(sysclk);
778c2ecf20Sopenharmony_ci	return 1;
788c2ecf20Sopenharmony_ci}
79