void imx_dump_clocks(void) { printf("mpll: %10u kHz\n", imx_get_mpllclk() / 1000); printf("arm: %10u kHz\n", imx_get_armclk() / 1000); printf("ioclk0: %10u kHz\n", imx_get_ioclk(0) / 1000); printf("ioclk1: %10u kHz\n", imx_get_ioclk(1) / 1000); printf("emiclk: %10u kHz\n", imx_get_emiclk() / 1000); printf("hclk: %10u kHz\n", imx_get_hclk() / 1000); printf("xclk: %10u kHz\n", imx_get_xclk() / 1000); printf("ssp0: %10u kHz\n", imx_get_sspclk(0) / 1000); printf("ssp1: %10u kHz\n", imx_get_sspclk(1) / 1000); printf("ssp2: %10u kHz\n", imx_get_sspclk(2) / 1000); printf("ssp3: %10u kHz\n", imx_get_sspclk(3) / 1000); }
unsigned imx_set_hclk(unsigned nc) { unsigned root_rate = imx_get_armclk(); unsigned reg, div; div = DIV_ROUND_UP(root_rate, nc); if ((div == 0) || (div >= 32)) return 0; if ((root_rate < nc) && (root_rate == 64000000)) div = 3; reg = readl(IMX_CCM_BASE + HW_CLKCTRL_HBUS) & ~0x3f; writel(reg | div, IMX_CCM_BASE + HW_CLKCTRL_HBUS); while (readl(IMX_CCM_BASE + HW_CLKCTRL_HBUS) & (1 << 31)) ; return imx_get_hclk(); }
unsigned imx_get_fecclk(void) { return imx_get_hclk(); }
static ssize_t mxs_ocotp_cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags) { struct ocotp_priv *priv = cdev->priv; void __iomem *base = priv->base; const char *write_param; unsigned int write_enabled = 0; unsigned long old_hclk, aligned_offset; int old_vddio, num_words, num_bytes, i, ret = 0; u8 *work_buf; u32 reg; write_param = dev_get_param(cdev->dev, "permanent_write_enable"); if (write_param) write_enabled = simple_strtoul(write_param, NULL, 0); if (!write_param || !write_enabled) return -EPERM; /* we can only work on u32, so calc some helpers */ aligned_offset = offset & ~3UL; num_words = DIV_ROUND_UP(offset - aligned_offset + count, 4); num_bytes = num_words << 2; /* read in all words which will be modified */ work_buf = xmalloc(num_bytes); i = mxs_ocotp_cdev_read(cdev, work_buf, num_bytes, aligned_offset, 0); if (i != num_bytes) { ret = -ENXIO; goto free_mem; } /* modify read words with to be written data */ for (i = 0; i < count; i++) work_buf[offset - aligned_offset + i] |= ((u8 *)buf)[i]; /* prepare system for OTP write */ old_hclk = imx_get_hclk(); old_vddio = imx_get_vddio(); imx_set_hclk(24000000); imx_set_vddio(2800000); writel(OCOTP_CTRL_RD_BANK_OPEN, base + OCOTP_CTRL + BIT_CLR); if (mxs_ocotp_wait_busy(priv)) { ret = -ETIMEDOUT; goto restore_system; } /* write word for word via data register */ for (i = 0; i < num_words; i++) { reg = readl(base + OCOTP_CTRL) & ~OCOTP_CTRL_ADDR_MASK; reg |= OCOTP_CTRL_WR_UNLOCK | ((aligned_offset >> 2) + i); writel(reg, base + OCOTP_CTRL); writel(((u32 *)work_buf)[i], base + OCOTP_DATA); if (mxs_ocotp_wait_busy(priv)) { ret = -ETIMEDOUT; goto restore_system; } mdelay(2); } restore_system: imx_set_vddio(old_vddio); imx_set_hclk(old_hclk); free_mem: free(work_buf); return ret; }