^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // Copyright (c) 2006-2008 Simtec Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) // http://armlinux.simtec.co.uk/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) // Ben Dooks <ben@simtec.co.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) // S3C2412/S3C2443 (PL093 based) IO timing support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/amba/pl093.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/mach/arch.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/mach/map.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "cpu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/soc/samsung/s3c-cpufreq-core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "s3c2412.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define print_ns(x) ((x) / 10), ((x) % 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * s3c2412_print_timing - print timing information via printk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * @pfx: The prefix to print each line with.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * @iot: The IO timing information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static void s3c2412_print_timing(const char *pfx, struct s3c_iotimings *iot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct s3c2412_iobank_timing *bt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned int bank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) for (bank = 0; bank < MAX_BANKS; bank++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) bt = iot->bank[bank].io_2412;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (!bt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) printk(KERN_DEBUG "%s: %d: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n", pfx, bank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) print_ns(bt->idcy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) print_ns(bt->wstrd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) print_ns(bt->wstwr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) print_ns(bt->wstoen),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) print_ns(bt->wstwen),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) print_ns(bt->wstbrd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * to_div - turn a cycle length into a divisor setting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * @cyc_tns: The cycle time in 10ths of nanoseconds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * @clk_tns: The clock period in 10ths of nanoseconds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static inline unsigned int to_div(unsigned int cyc_tns, unsigned int clk_tns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return cyc_tns ? DIV_ROUND_UP(cyc_tns, clk_tns) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * calc_timing - calculate timing divisor value and check in range.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * @hwtm: The hardware timing in 10ths of nanoseconds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * @clk_tns: The clock period in 10ths of nanoseconds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * @err: Pointer to err variable to update in event of failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static unsigned int calc_timing(unsigned int hwtm, unsigned int clk_tns,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned int *err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) unsigned int ret = to_div(hwtm, clk_tns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (ret > 0xf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) *err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * s3c2412_calc_bank - calculate the bank divisor settings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * @cfg: The current frequency configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * @bt: The bank timing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int s3c2412_calc_bank(struct s3c_cpufreq_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct s3c2412_iobank_timing *bt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) unsigned int hclk = cfg->freq.hclk_tns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) bt->smbidcyr = calc_timing(bt->idcy, hclk, &err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) bt->smbwstrd = calc_timing(bt->wstrd, hclk, &err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) bt->smbwstwr = calc_timing(bt->wstwr, hclk, &err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) bt->smbwstoen = calc_timing(bt->wstoen, hclk, &err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) bt->smbwstwen = calc_timing(bt->wstwen, hclk, &err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) bt->smbwstbrd = calc_timing(bt->wstbrd, hclk, &err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * s3c2412_iotiming_debugfs - debugfs show io bank timing information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * @seq: The seq_file to write output to using seq_printf().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * @cfg: The current configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * @iob: The IO bank information to decode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) void s3c2412_iotiming_debugfs(struct seq_file *seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct s3c_cpufreq_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) union s3c_iobank *iob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct s3c2412_iobank_timing *bt = iob->io_2412;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) seq_printf(seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) "\tRead: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) print_ns(bt->idcy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) print_ns(bt->wstrd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) print_ns(bt->wstwr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) print_ns(bt->wstoen),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) print_ns(bt->wstwen),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) print_ns(bt->wstbrd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * s3c2412_iotiming_calc - calculate all the bank divisor settings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * @cfg: The current frequency configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * @iot: The bank timing information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * Calculate the timing information for all the banks that are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * configured as IO, using s3c2412_calc_bank().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) int s3c2412_iotiming_calc(struct s3c_cpufreq_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct s3c_iotimings *iot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct s3c2412_iobank_timing *bt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int bank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) for (bank = 0; bank < MAX_BANKS; bank++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) bt = iot->bank[bank].io_2412;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (!bt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ret = s3c2412_calc_bank(cfg, bt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) printk(KERN_ERR "%s: cannot calculate bank %d io\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) __func__, bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * s3c2412_iotiming_set - set the timing information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * @cfg: The current frequency configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * @iot: The bank timing information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * Set the IO bank information from the details calculated earlier from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * calling s3c2412_iotiming_calc().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) void s3c2412_iotiming_set(struct s3c_cpufreq_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct s3c_iotimings *iot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct s3c2412_iobank_timing *bt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) int bank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* set the io timings from the specifier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) for (bank = 0; bank < MAX_BANKS; bank++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) bt = iot->bank[bank].io_2412;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (!bt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) regs = S3C2412_SSMC_BANK(bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) __raw_writel(bt->smbidcyr, regs + SMBIDCYR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) __raw_writel(bt->smbwstrd, regs + SMBWSTRDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) __raw_writel(bt->smbwstwr, regs + SMBWSTWRR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) __raw_writel(bt->smbwstoen, regs + SMBWSTOENR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) __raw_writel(bt->smbwstwen, regs + SMBWSTWENR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) __raw_writel(bt->smbwstbrd, regs + SMBWSTBRDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) static inline unsigned int s3c2412_decode_timing(unsigned int clock, u32 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return (reg & 0xf) * clock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static void s3c2412_iotiming_getbank(struct s3c_cpufreq_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct s3c2412_iobank_timing *bt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) unsigned int bank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) unsigned long clk = cfg->freq.hclk_tns; /* ssmc clock??? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) void __iomem *regs = S3C2412_SSMC_BANK(bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) bt->idcy = s3c2412_decode_timing(clk, __raw_readl(regs + SMBIDCYR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) bt->wstrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTRDR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) bt->wstoen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTOENR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) bt->wstwen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTWENR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) bt->wstbrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTBRDR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * bank_is_io - return true if bank is (possibly) IO.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * @bank: The bank number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * @bankcfg: The value of S3C2412_EBI_BANKCFG.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static inline bool bank_is_io(unsigned int bank, u32 bankcfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (bank < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return !(bankcfg & (1 << bank));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) int s3c2412_iotiming_get(struct s3c_cpufreq_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct s3c_iotimings *timings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) struct s3c2412_iobank_timing *bt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) u32 bankcfg = __raw_readl(S3C2412_EBI_BANKCFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) unsigned int bank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* look through all banks to see what is currently set. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) for (bank = 0; bank < MAX_BANKS; bank++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (!bank_is_io(bank, bankcfg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) bt = kzalloc(sizeof(*bt), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (!bt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) timings->bank[bank].io_2412 = bt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) s3c2412_iotiming_getbank(cfg, bt, bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) s3c2412_print_timing("get", timings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* this is in here as it is so small, it doesn't currently warrant a file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * to itself. We expect that any s3c24xx needing this is going to also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * need the iotiming support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) void s3c2412_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct s3c_cpufreq_board *board = cfg->board;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) u32 refresh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) WARN_ON(board == NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /* Reduce both the refresh time (in ns) and the frequency (in MHz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * down to ensure that we do not overflow 32 bit numbers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * This should work for HCLK up to 133MHz and refresh period up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * to 30usec.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) refresh = (cfg->freq.hclk / 100) * (board->refresh / 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) refresh = DIV_ROUND_UP(refresh, (1000 * 1000)); /* apply scale */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) refresh &= ((1 << 16) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) s3c_freq_dbg("%s: refresh value %u\n", __func__, (unsigned int)refresh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) __raw_writel(refresh, S3C2412_REFRESH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }