162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Support code for virtual Ranchu board for MIPS. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Miodrag Dinic <miodrag.dinic@mips.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/of_address.h> 962306a36Sopenharmony_ci#include <linux/types.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <asm/machine.h> 1262306a36Sopenharmony_ci#include <asm/mipsregs.h> 1362306a36Sopenharmony_ci#include <asm/time.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define GOLDFISH_TIMER_LOW 0x00 1662306a36Sopenharmony_ci#define GOLDFISH_TIMER_HIGH 0x04 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic __init u64 read_rtc_time(void __iomem *base) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci u32 time_low; 2162306a36Sopenharmony_ci u32 time_high; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci /* 2462306a36Sopenharmony_ci * Reading the low address latches the high value 2562306a36Sopenharmony_ci * as well so there is no fear that we may read 2662306a36Sopenharmony_ci * inaccurate high value. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci time_low = readl(base + GOLDFISH_TIMER_LOW); 2962306a36Sopenharmony_ci time_high = readl(base + GOLDFISH_TIMER_HIGH); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci return ((u64)time_high << 32) | time_low; 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic __init unsigned int ranchu_measure_hpt_freq(void) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci u64 rtc_start, rtc_current, rtc_delta; 3762306a36Sopenharmony_ci unsigned int start, count; 3862306a36Sopenharmony_ci struct device_node *np; 3962306a36Sopenharmony_ci void __iomem *rtc_base; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "google,goldfish-rtc"); 4262306a36Sopenharmony_ci if (!np) 4362306a36Sopenharmony_ci panic("%s(): Failed to find 'google,goldfish-rtc' dt node!", 4462306a36Sopenharmony_ci __func__); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci rtc_base = of_iomap(np, 0); 4762306a36Sopenharmony_ci of_node_put(np); 4862306a36Sopenharmony_ci if (!rtc_base) 4962306a36Sopenharmony_ci panic("%s(): Failed to ioremap Goldfish RTC base!", __func__); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* 5262306a36Sopenharmony_ci * Poll the nanosecond resolution RTC for one 5362306a36Sopenharmony_ci * second to calibrate the CPU frequency. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci rtc_start = read_rtc_time(rtc_base); 5662306a36Sopenharmony_ci start = read_c0_count(); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci do { 5962306a36Sopenharmony_ci rtc_current = read_rtc_time(rtc_base); 6062306a36Sopenharmony_ci rtc_delta = rtc_current - rtc_start; 6162306a36Sopenharmony_ci } while (rtc_delta < NSEC_PER_SEC); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci count = read_c0_count() - start; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* 6662306a36Sopenharmony_ci * Make sure the frequency will be a round number. 6762306a36Sopenharmony_ci * Without this correction, the returned value may vary 6862306a36Sopenharmony_ci * between subsequent emulation executions. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * TODO: Set this value using device tree. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci count += 5000; 7362306a36Sopenharmony_ci count -= count % 10000; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci iounmap(rtc_base); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return count; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic const struct of_device_id ranchu_of_match[] __initconst = { 8162306a36Sopenharmony_ci { 8262306a36Sopenharmony_ci .compatible = "mti,ranchu", 8362306a36Sopenharmony_ci }, 8462306a36Sopenharmony_ci {} 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ciMIPS_MACHINE(ranchu) = { 8862306a36Sopenharmony_ci .matches = ranchu_of_match, 8962306a36Sopenharmony_ci .measure_hpt_freq = ranchu_measure_hpt_freq, 9062306a36Sopenharmony_ci}; 91