18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
58c2ecf20Sopenharmony_ci * Copyright (C) 2010 John Crispin <john@phrozen.org>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/io.h>
88c2ecf20Sopenharmony_ci#include <linux/export.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/types.h>
128c2ecf20Sopenharmony_ci#include <linux/clk.h>
138c2ecf20Sopenharmony_ci#include <linux/clkdev.h>
148c2ecf20Sopenharmony_ci#include <linux/err.h>
158c2ecf20Sopenharmony_ci#include <linux/list.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <asm/time.h>
188c2ecf20Sopenharmony_ci#include <asm/irq.h>
198c2ecf20Sopenharmony_ci#include <asm/div64.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <lantiq_soc.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "clk.h"
248c2ecf20Sopenharmony_ci#include "prom.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* lantiq socs have 3 static clocks */
278c2ecf20Sopenharmony_cistatic struct clk cpu_clk_generic[4];
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_civoid clkdev_add_static(unsigned long cpu, unsigned long fpi,
308c2ecf20Sopenharmony_ci			unsigned long io, unsigned long ppe)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	cpu_clk_generic[0].rate = cpu;
338c2ecf20Sopenharmony_ci	cpu_clk_generic[1].rate = fpi;
348c2ecf20Sopenharmony_ci	cpu_clk_generic[2].rate = io;
358c2ecf20Sopenharmony_ci	cpu_clk_generic[3].rate = ppe;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct clk *clk_get_cpu(void)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	return &cpu_clk_generic[0];
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct clk *clk_get_fpi(void)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	return &cpu_clk_generic[1];
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_get_fpi);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct clk *clk_get_io(void)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	return &cpu_clk_generic[2];
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_get_io);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistruct clk *clk_get_ppe(void)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	return &cpu_clk_generic[3];
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_get_ppe);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic inline int clk_good(struct clk *clk)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	return clk && !IS_ERR(clk);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciunsigned long clk_get_rate(struct clk *clk)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	if (unlikely(!clk_good(clk)))
698c2ecf20Sopenharmony_ci		return 0;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (clk->rate != 0)
728c2ecf20Sopenharmony_ci		return clk->rate;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (clk->get_rate != NULL)
758c2ecf20Sopenharmony_ci		return clk->get_rate();
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return 0;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_get_rate);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ciint clk_set_rate(struct clk *clk, unsigned long rate)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	if (unlikely(!clk_good(clk)))
848c2ecf20Sopenharmony_ci		return 0;
858c2ecf20Sopenharmony_ci	if (clk->rates && *clk->rates) {
868c2ecf20Sopenharmony_ci		unsigned long *r = clk->rates;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		while (*r && (*r != rate))
898c2ecf20Sopenharmony_ci			r++;
908c2ecf20Sopenharmony_ci		if (!*r) {
918c2ecf20Sopenharmony_ci			pr_err("clk %s.%s: trying to set invalid rate %ld\n",
928c2ecf20Sopenharmony_ci				clk->cl.dev_id, clk->cl.con_id, rate);
938c2ecf20Sopenharmony_ci			return -1;
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci	clk->rate = rate;
978c2ecf20Sopenharmony_ci	return 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_set_rate);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cilong clk_round_rate(struct clk *clk, unsigned long rate)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	if (unlikely(!clk_good(clk)))
1048c2ecf20Sopenharmony_ci		return 0;
1058c2ecf20Sopenharmony_ci	if (clk->rates && *clk->rates) {
1068c2ecf20Sopenharmony_ci		unsigned long *r = clk->rates;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		while (*r && (*r != rate))
1098c2ecf20Sopenharmony_ci			r++;
1108c2ecf20Sopenharmony_ci		if (!*r) {
1118c2ecf20Sopenharmony_ci			return clk->rate;
1128c2ecf20Sopenharmony_ci		}
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	return rate;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_round_rate);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ciint clk_enable(struct clk *clk)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	if (unlikely(!clk_good(clk)))
1218c2ecf20Sopenharmony_ci		return -1;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (clk->enable)
1248c2ecf20Sopenharmony_ci		return clk->enable(clk);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	return -1;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_enable);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_civoid clk_disable(struct clk *clk)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	if (unlikely(!clk_good(clk)))
1338c2ecf20Sopenharmony_ci		return;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (clk->disable)
1368c2ecf20Sopenharmony_ci		clk->disable(clk);
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_disable);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ciint clk_activate(struct clk *clk)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	if (unlikely(!clk_good(clk)))
1438c2ecf20Sopenharmony_ci		return -1;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (clk->activate)
1468c2ecf20Sopenharmony_ci		return clk->activate(clk);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return -1;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_activate);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_civoid clk_deactivate(struct clk *clk)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	if (unlikely(!clk_good(clk)))
1558c2ecf20Sopenharmony_ci		return;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (clk->deactivate)
1588c2ecf20Sopenharmony_ci		clk->deactivate(clk);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_deactivate);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistruct clk *clk_get_parent(struct clk *clk)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	return NULL;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_get_parent);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ciint clk_set_parent(struct clk *clk, struct clk *parent)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_set_parent);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic inline u32 get_counter_resolution(void)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	u32 res;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1798c2ecf20Sopenharmony_ci		".set	push\n"
1808c2ecf20Sopenharmony_ci		".set	mips32r2\n"
1818c2ecf20Sopenharmony_ci		"rdhwr	%0, $3\n"
1828c2ecf20Sopenharmony_ci		".set pop\n"
1838c2ecf20Sopenharmony_ci		: "=&r" (res)
1848c2ecf20Sopenharmony_ci		: /* no input */
1858c2ecf20Sopenharmony_ci		: "memory");
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	return res;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_civoid __init plat_time_init(void)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	struct clk *clk;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	ltq_soc_init();
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	clk = clk_get_cpu();
1978c2ecf20Sopenharmony_ci	mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution();
1988c2ecf20Sopenharmony_ci	write_c0_compare(read_c0_count());
1998c2ecf20Sopenharmony_ci	pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
2008c2ecf20Sopenharmony_ci	clk_put(clk);
2018c2ecf20Sopenharmony_ci}
202