|
@@ -324,3 +324,155 @@ void s3c2410_iotiming_debugfs(struct seq_file *seq,
|
|
unsigned int tcoh;
|
|
unsigned int tcoh;
|
|
unsigned int tcah;
|
|
unsigned int tcah;
|
|
|
|
|
|
|
|
+ seq_printf(seq, "BANKCON=0x%08lx\n", bankcon);
|
|
|
|
+
|
|
|
|
+ tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT);
|
|
|
|
+ tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT);
|
|
|
|
+ tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT);
|
|
|
|
+ tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT);
|
|
|
|
+ tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
|
|
|
|
+
|
|
|
|
+ seq_printf(seq,
|
|
|
|
+ "\tRead: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
|
|
|
|
+ print_ns(bt->tacs),
|
|
|
|
+ print_ns(bt->tcos),
|
|
|
|
+ print_ns(bt->tacc),
|
|
|
|
+ print_ns(bt->tcoh),
|
|
|
|
+ print_ns(bt->tcah));
|
|
|
|
+
|
|
|
|
+ seq_printf(seq,
|
|
|
|
+ "\t Set: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
|
|
|
|
+ print_ns(tacs),
|
|
|
|
+ print_ns(tcos),
|
|
|
|
+ print_ns(tacc),
|
|
|
|
+ print_ns(tcoh),
|
|
|
|
+ print_ns(tcah));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * s3c2410_iotiming_calc - Calculate bank timing for frequency change.
|
|
|
|
+ * @cfg: The frequency configuration
|
|
|
|
+ * @iot: The IO timing information to fill out.
|
|
|
|
+ *
|
|
|
|
+ * Calculate the new values for the banks in @iot based on the new
|
|
|
|
+ * frequency information in @cfg. This is then used by s3c2410_iotiming_set()
|
|
|
|
+ * to update the timing when necessary.
|
|
|
|
+ */
|
|
|
|
+int s3c2410_iotiming_calc(struct s3c_cpufreq_config *cfg,
|
|
|
|
+ struct s3c_iotimings *iot)
|
|
|
|
+{
|
|
|
|
+ struct s3c2410_iobank_timing *bt;
|
|
|
|
+ unsigned long bankcon;
|
|
|
|
+ int bank;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ for (bank = 0; bank < MAX_BANKS; bank++) {
|
|
|
|
+ bankcon = __raw_readl(bank_reg(bank));
|
|
|
|
+ bt = iot->bank[bank].io_2410;
|
|
|
|
+
|
|
|
|
+ if (!bt)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ bt->bankcon = bankcon;
|
|
|
|
+
|
|
|
|
+ ret = s3c2410_calc_bank(cfg, bt);
|
|
|
|
+ if (ret) {
|
|
|
|
+ printk(KERN_ERR "%s: cannot calculate bank %d io\n",
|
|
|
|
+ __func__, bank);
|
|
|
|
+ goto err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ s3c_freq_iodbg("%s: bank %d: con=%08lx\n",
|
|
|
|
+ __func__, bank, bt->bankcon);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+ err:
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * s3c2410_iotiming_set - set the IO timings from the given setup.
|
|
|
|
+ * @cfg: The frequency configuration
|
|
|
|
+ * @iot: The IO timing information to use.
|
|
|
|
+ *
|
|
|
|
+ * Set all the currently used IO bank timing information generated
|
|
|
|
+ * by s3c2410_iotiming_calc() once the core has validated that all
|
|
|
|
+ * the new values are within permitted bounds.
|
|
|
|
+ */
|
|
|
|
+void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg,
|
|
|
|
+ struct s3c_iotimings *iot)
|
|
|
|
+{
|
|
|
|
+ struct s3c2410_iobank_timing *bt;
|
|
|
|
+ int bank;
|
|
|
|
+
|
|
|
|
+ /* set the io timings from the specifier */
|
|
|
|
+
|
|
|
|
+ for (bank = 0; bank < MAX_BANKS; bank++) {
|
|
|
|
+ bt = iot->bank[bank].io_2410;
|
|
|
|
+ if (!bt)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ __raw_writel(bt->bankcon, bank_reg(bank));
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * s3c2410_iotiming_get - Get the timing information from current registers.
|
|
|
|
+ * @cfg: The frequency configuration
|
|
|
|
+ * @timings: The IO timing information to fill out.
|
|
|
|
+ *
|
|
|
|
+ * Calculate the @timings timing information from the current frequency
|
|
|
|
+ * information in @cfg, and the new frequency configur
|
|
|
|
+ * through all the IO banks, reading the state and then updating @iot
|
|
|
|
+ * as necessary.
|
|
|
|
+ *
|
|
|
|
+ * This is used at the moment on initialisation to get the current
|
|
|
|
+ * configuration so that boards do not have to carry their own setup
|
|
|
|
+ * if the timings are correct on initialisation.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+int s3c2410_iotiming_get(struct s3c_cpufreq_config *cfg,
|
|
|
|
+ struct s3c_iotimings *timings)
|
|
|
|
+{
|
|
|
|
+ struct s3c2410_iobank_timing *bt;
|
|
|
|
+ unsigned long bankcon;
|
|
|
|
+ unsigned long bwscon;
|
|
|
|
+ int bank;
|
|
|
|
+
|
|
|
|
+ bwscon = __raw_readl(S3C2410_BWSCON);
|
|
|
|
+
|
|
|
|
+ /* look through all banks to see what is currently set. */
|
|
|
|
+
|
|
|
|
+ for (bank = 0; bank < MAX_BANKS; bank++) {
|
|
|
|
+ bankcon = __raw_readl(bank_reg(bank));
|
|
|
|
+
|
|
|
|
+ if (!bank_is_io(bankcon))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ s3c_freq_iodbg("%s: bank %d: con %08lx\n",
|
|
|
|
+ __func__, bank, bankcon);
|
|
|
|
+
|
|
|
|
+ bt = kzalloc(sizeof(struct s3c2410_iobank_timing), GFP_KERNEL);
|
|
|
|
+ if (!bt) {
|
|
|
|
+ printk(KERN_ERR "%s: no memory for bank\n", __func__);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* find out in nWait is enabled for bank. */
|
|
|
|
+
|
|
|
|
+ if (bank != 0) {
|
|
|
|
+ unsigned long tmp = S3C2410_BWSCON_GET(bwscon, bank);
|
|
|
|
+ if (tmp & S3C2410_BWSCON_WS)
|
|
|
|
+ bt->nwait_en = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ timings->bank[bank].io_2410 = bt;
|
|
|
|
+ bt->bankcon = bankcon;
|
|
|
|
+
|
|
|
|
+ s3c2410_iotiming_getbank(cfg, bt);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ s3c2410_print_timing("get", timings);
|
|
|
|
+ return 0;
|
|
|
|
+}
|