/* sm501_init_reg
*
* Helper function for the init code to setup a register
+ *
+ * clear the bits which are set in r->mask, and then set
+ * the bits set in r->set.
*/
static inline void sm501_init_reg(struct sm501_devdata *sm,
unsigned long tmp;
tmp = readl(sm->regs + reg);
- tmp |= r->set;
tmp &= ~r->mask;
+ tmp |= r->set;
writel(tmp, sm->regs + reg);
}
sm501_init_reg(sm, SM501_GPIO31_0_CONTROL, &init->gpio_low);
sm501_init_reg(sm, SM501_GPIO63_32_CONTROL, &init->gpio_high);
+ if (init->m1xclk) {
+ dev_info(sm->dev, "setting M1XCLK to %ld\n", init->m1xclk);
+ sm501_set_clock(sm->dev, SM501_CLOCK_M1XCLK, init->m1xclk);
+ }
+
if (init->mclk) {
dev_info(sm->dev, "setting MCLK to %ld\n", init->mclk);
sm501_set_clock(sm->dev, SM501_CLOCK_MCLK, init->mclk);
}
- if (init->m1xclk) {
- dev_info(sm->dev, "setting M1XCLK to %ld\n", init->m1xclk);
- sm501_set_clock(sm->dev, SM501_CLOCK_M1XCLK, init->m1xclk);
- }
+}
+
+/* Check the PLL sources for the M1CLK and M1XCLK
+ *
+ * If the M1CLK and M1XCLKs are not sourced from the same PLL, then
+ * there is a risk (see errata AB-5) that the SM501 will cease proper
+ * function. If this happens, then it is likely the SM501 will
+ * hang the system.
+*/
+
+static int sm501_check_clocks(struct sm501_devdata *sm)
+{
+ unsigned long pwrmode = readl(sm->regs + SM501_CURRENT_CLOCK);
+ unsigned long msrc = (pwrmode & SM501_POWERMODE_M_SRC);
+ unsigned long m1src = (pwrmode & SM501_POWERMODE_M1_SRC);
+
+ return ((msrc == 0 && m1src != 0) || (msrc != 0 && m1src == 0));
}
static unsigned int sm501_mem_local[] = {
{
resource_size_t mem_avail;
unsigned long dramctrl;
+ unsigned long devid;
int ret;
mutex_init(&sm->clock_lock);
INIT_LIST_HEAD(&sm->devices);
- dramctrl = readl(sm->regs + SM501_DRAM_CONTROL);
+ devid = readl(sm->regs + SM501_DEVICEID);
+ if ((devid & SM501_DEVICEID_IDMASK) != SM501_DEVICEID_SM501) {
+ dev_err(sm->dev, "incorrect device id %08lx\n", devid);
+ return -EINVAL;
+ }
+
+ dramctrl = readl(sm->regs + SM501_DRAM_CONTROL);
mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7];
- dev_info(sm->dev, "SM501 At %p: Version %08x, %ld Mb, IRQ %d\n",
- sm->regs, readl(sm->regs + SM501_DEVICEID),
- (unsigned long)mem_avail >> 20, sm->irq);
+ dev_info(sm->dev, "SM501 At %p: Version %08lx, %ld Mb, IRQ %d\n",
+ sm->regs, devid, (unsigned long)mem_avail >> 20, sm->irq);
sm501_dump_gate(sm);
}
}
+ ret = sm501_check_clocks(sm);
+ if (ret) {
+ dev_err(sm->dev, "M1X and M clocks sourced from different "
+ "PLLs\n");
+ return -EINVAL;
+ }
+
/* always create a framebuffer */
sm501_register_display(sm, &mem_avail);
},
.devices = SM501_USE_ALL,
- .mclk = 100 * MHZ,
- .m1xclk = 160 * MHZ,
+
+ /* Errata AB-3 says that 72MHz is the fastest available
+ * for 33MHZ PCI with proper bus-mastering operation */
+
+ .mclk = 72 * MHZ,
+ .m1xclk = 144 * MHZ,
};
static struct sm501_platdata_fbsub sm501_pdata_fbsub = {