Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
0004  *
0005  * Author: John Rigby <jrigby@freescale.com>
0006  *
0007  * Description:
0008  * MPC512x Shared code
0009  */
0010 
0011 #include <linux/clk.h>
0012 #include <linux/kernel.h>
0013 #include <linux/io.h>
0014 #include <linux/irq.h>
0015 #include <linux/of_address.h>
0016 #include <linux/of_platform.h>
0017 #include <linux/fsl-diu-fb.h>
0018 #include <linux/memblock.h>
0019 #include <sysdev/fsl_soc.h>
0020 
0021 #include <asm/cacheflush.h>
0022 #include <asm/machdep.h>
0023 #include <asm/ipic.h>
0024 #include <asm/time.h>
0025 #include <asm/mpc5121.h>
0026 #include <asm/mpc52xx_psc.h>
0027 
0028 #include "mpc512x.h"
0029 
0030 static struct mpc512x_reset_module __iomem *reset_module_base;
0031 
0032 static void __init mpc512x_restart_init(void)
0033 {
0034     struct device_node *np;
0035     const char *reset_compat;
0036 
0037     reset_compat = mpc512x_select_reset_compat();
0038     np = of_find_compatible_node(NULL, NULL, reset_compat);
0039     if (!np)
0040         return;
0041 
0042     reset_module_base = of_iomap(np, 0);
0043     of_node_put(np);
0044 }
0045 
0046 void __noreturn mpc512x_restart(char *cmd)
0047 {
0048     if (reset_module_base) {
0049         /* Enable software reset "RSTE" */
0050         out_be32(&reset_module_base->rpr, 0x52535445);
0051         /* Set software hard reset */
0052         out_be32(&reset_module_base->rcr, 0x2);
0053     } else {
0054         pr_err("Restart module not mapped.\n");
0055     }
0056     for (;;)
0057         ;
0058 }
0059 
0060 struct fsl_diu_shared_fb {
0061     u8      gamma[0x300];   /* 32-bit aligned! */
0062     struct diu_ad   ad0;        /* 32-bit aligned! */
0063     phys_addr_t fb_phys;
0064     size_t      fb_len;
0065     bool        in_use;
0066 };
0067 
0068 /* receives a pixel clock spec in pico seconds, adjusts the DIU clock rate */
0069 static void mpc512x_set_pixel_clock(unsigned int pixclock)
0070 {
0071     struct device_node *np;
0072     struct clk *clk_diu;
0073     unsigned long epsilon, minpixclock, maxpixclock;
0074     unsigned long offset, want, got, delta;
0075 
0076     /* lookup and enable the DIU clock */
0077     np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
0078     if (!np) {
0079         pr_err("Could not find DIU device tree node.\n");
0080         return;
0081     }
0082     clk_diu = of_clk_get(np, 0);
0083     if (IS_ERR(clk_diu)) {
0084         /* backwards compat with device trees that lack clock specs */
0085         clk_diu = clk_get_sys(np->name, "ipg");
0086     }
0087     of_node_put(np);
0088     if (IS_ERR(clk_diu)) {
0089         pr_err("Could not lookup DIU clock.\n");
0090         return;
0091     }
0092     if (clk_prepare_enable(clk_diu)) {
0093         pr_err("Could not enable DIU clock.\n");
0094         return;
0095     }
0096 
0097     /*
0098      * convert the picoseconds spec into the desired clock rate,
0099      * determine the acceptable clock range for the monitor (+/- 5%),
0100      * do the calculation in steps to avoid integer overflow
0101      */
0102     pr_debug("DIU pixclock in ps - %u\n", pixclock);
0103     pixclock = (1000000000 / pixclock) * 1000;
0104     pr_debug("DIU pixclock freq  - %u\n", pixclock);
0105     epsilon = pixclock / 20; /* pixclock * 0.05 */
0106     pr_debug("DIU deviation      - %lu\n", epsilon);
0107     minpixclock = pixclock - epsilon;
0108     maxpixclock = pixclock + epsilon;
0109     pr_debug("DIU minpixclock    - %lu\n", minpixclock);
0110     pr_debug("DIU maxpixclock    - %lu\n", maxpixclock);
0111 
0112     /*
0113      * check whether the DIU supports the desired pixel clock
0114      *
0115      * - simply request the desired clock and see what the
0116      *   platform's clock driver will make of it, assuming that it
0117      *   will setup the best approximation of the requested value
0118      * - try other candidate frequencies in the order of decreasing
0119      *   preference (i.e. with increasing distance from the desired
0120      *   pixel clock, and checking the lower frequency before the
0121      *   higher frequency to not overload the hardware) until the
0122      *   first match is found -- any potential subsequent match
0123      *   would only be as good as the former match or typically
0124      *   would be less preferrable
0125      *
0126      * the offset increment of pixelclock divided by 64 is an
0127      * arbitrary choice -- it's simple to calculate, in the typical
0128      * case we expect the first check to succeed already, in the
0129      * worst case seven frequencies get tested (the exact center and
0130      * three more values each to the left and to the right) before
0131      * the 5% tolerance window is exceeded, resulting in fast enough
0132      * execution yet high enough probability of finding a suitable
0133      * value, while the error rate will be in the order of single
0134      * percents
0135      */
0136     for (offset = 0; offset <= epsilon; offset += pixclock / 64) {
0137         want = pixclock - offset;
0138         pr_debug("DIU checking clock - %lu\n", want);
0139         clk_set_rate(clk_diu, want);
0140         got = clk_get_rate(clk_diu);
0141         delta = abs(pixclock - got);
0142         if (delta < epsilon)
0143             break;
0144         if (!offset)
0145             continue;
0146         want = pixclock + offset;
0147         pr_debug("DIU checking clock - %lu\n", want);
0148         clk_set_rate(clk_diu, want);
0149         got = clk_get_rate(clk_diu);
0150         delta = abs(pixclock - got);
0151         if (delta < epsilon)
0152             break;
0153     }
0154     if (offset <= epsilon) {
0155         pr_debug("DIU clock accepted - %lu\n", want);
0156         pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n",
0157              pixclock, got, delta, epsilon);
0158         return;
0159     }
0160     pr_warn("DIU pixclock auto search unsuccessful\n");
0161 
0162     /*
0163      * what is the most appropriate action to take when the search
0164      * for an available pixel clock which is acceptable to the
0165      * monitor has failed?  disable the DIU (clock) or just provide
0166      * a "best effort"?  we go with the latter
0167      */
0168     pr_warn("DIU pixclock best effort fallback (backend's choice)\n");
0169     clk_set_rate(clk_diu, pixclock);
0170     got = clk_get_rate(clk_diu);
0171     delta = abs(pixclock - got);
0172     pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n",
0173          pixclock, got, delta, epsilon);
0174 }
0175 
0176 static enum fsl_diu_monitor_port
0177 mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port)
0178 {
0179     return FSL_DIU_PORT_DVI;
0180 }
0181 
0182 static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
0183 
0184 static inline void mpc512x_free_bootmem(struct page *page)
0185 {
0186     BUG_ON(PageTail(page));
0187     BUG_ON(page_ref_count(page) > 1);
0188     free_reserved_page(page);
0189 }
0190 
0191 static void mpc512x_release_bootmem(void)
0192 {
0193     unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK;
0194     unsigned long size = diu_shared_fb.fb_len;
0195     unsigned long start, end;
0196 
0197     if (diu_shared_fb.in_use) {
0198         start = PFN_UP(addr);
0199         end = PFN_DOWN(addr + size);
0200 
0201         for (; start < end; start++)
0202             mpc512x_free_bootmem(pfn_to_page(start));
0203 
0204         diu_shared_fb.in_use = false;
0205     }
0206     diu_ops.release_bootmem = NULL;
0207 }
0208 
0209 /*
0210  * Check if DIU was pre-initialized. If so, perform steps
0211  * needed to continue displaying through the whole boot process.
0212  * Move area descriptor and gamma table elsewhere, they are
0213  * destroyed by bootmem allocator otherwise. The frame buffer
0214  * address range will be reserved in setup_arch() after bootmem
0215  * allocator is up.
0216  */
0217 static void __init mpc512x_init_diu(void)
0218 {
0219     struct device_node *np;
0220     struct diu __iomem *diu_reg;
0221     phys_addr_t desc;
0222     void __iomem *vaddr;
0223     unsigned long mode, pix_fmt, res, bpp;
0224     unsigned long dst;
0225 
0226     np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
0227     if (!np) {
0228         pr_err("No DIU node\n");
0229         return;
0230     }
0231 
0232     diu_reg = of_iomap(np, 0);
0233     of_node_put(np);
0234     if (!diu_reg) {
0235         pr_err("Can't map DIU\n");
0236         return;
0237     }
0238 
0239     mode = in_be32(&diu_reg->diu_mode);
0240     if (mode == MFB_MODE0) {
0241         pr_info("%s: DIU OFF\n", __func__);
0242         goto out;
0243     }
0244 
0245     desc = in_be32(&diu_reg->desc[0]);
0246     vaddr = ioremap(desc, sizeof(struct diu_ad));
0247     if (!vaddr) {
0248         pr_err("Can't map DIU area desc.\n");
0249         goto out;
0250     }
0251     memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad));
0252     /* flush fb area descriptor */
0253     dst = (unsigned long)&diu_shared_fb.ad0;
0254     flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1);
0255 
0256     res = in_be32(&diu_reg->disp_size);
0257     pix_fmt = in_le32(vaddr);
0258     bpp = ((pix_fmt >> 16) & 0x3) + 1;
0259     diu_shared_fb.fb_phys = in_le32(vaddr + 4);
0260     diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp;
0261     diu_shared_fb.in_use = true;
0262     iounmap(vaddr);
0263 
0264     desc = in_be32(&diu_reg->gamma);
0265     vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma));
0266     if (!vaddr) {
0267         pr_err("Can't map DIU area desc.\n");
0268         diu_shared_fb.in_use = false;
0269         goto out;
0270     }
0271     memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma));
0272     /* flush gamma table */
0273     dst = (unsigned long)&diu_shared_fb.gamma;
0274     flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1);
0275 
0276     iounmap(vaddr);
0277     out_be32(&diu_reg->gamma, virt_to_phys(&diu_shared_fb.gamma));
0278     out_be32(&diu_reg->desc[1], 0);
0279     out_be32(&diu_reg->desc[2], 0);
0280     out_be32(&diu_reg->desc[0], virt_to_phys(&diu_shared_fb.ad0));
0281 
0282 out:
0283     iounmap(diu_reg);
0284 }
0285 
0286 static void __init mpc512x_setup_diu(void)
0287 {
0288     int ret;
0289 
0290     /*
0291      * We do not allocate and configure new area for bitmap buffer
0292      * because it would require copying bitmap data (splash image)
0293      * and so negatively affect boot time. Instead we reserve the
0294      * already configured frame buffer area so that it won't be
0295      * destroyed. The starting address of the area to reserve and
0296      * also it's length is passed to memblock_reserve(). It will be
0297      * freed later on first open of fbdev, when splash image is not
0298      * needed any more.
0299      */
0300     if (diu_shared_fb.in_use) {
0301         ret = memblock_reserve(diu_shared_fb.fb_phys,
0302                        diu_shared_fb.fb_len);
0303         if (ret) {
0304             pr_err("%s: reserve bootmem failed\n", __func__);
0305             diu_shared_fb.in_use = false;
0306         }
0307     }
0308 
0309     diu_ops.set_pixel_clock     = mpc512x_set_pixel_clock;
0310     diu_ops.valid_monitor_port  = mpc512x_valid_monitor_port;
0311     diu_ops.release_bootmem     = mpc512x_release_bootmem;
0312 }
0313 
0314 void __init mpc512x_init_IRQ(void)
0315 {
0316     struct device_node *np;
0317 
0318     np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ipic");
0319     if (!np)
0320         return;
0321 
0322     ipic_init(np, 0);
0323     of_node_put(np);
0324 
0325     /*
0326      * Initialize the default interrupt mapping priorities,
0327      * in case the boot rom changed something on us.
0328      */
0329     ipic_set_default_priority();
0330 }
0331 
0332 /*
0333  * Nodes to do bus probe on, soc and localbus
0334  */
0335 static const struct of_device_id of_bus_ids[] __initconst = {
0336     { .compatible = "fsl,mpc5121-immr", },
0337     { .compatible = "fsl,mpc5121-localbus", },
0338     { .compatible = "fsl,mpc5121-mbx", },
0339     { .compatible = "fsl,mpc5121-nfc", },
0340     { .compatible = "fsl,mpc5121-sram", },
0341     { .compatible = "fsl,mpc5121-pci", },
0342     { .compatible = "gpio-leds", },
0343     {},
0344 };
0345 
0346 static void __init mpc512x_declare_of_platform_devices(void)
0347 {
0348     if (of_platform_bus_probe(NULL, of_bus_ids, NULL))
0349         printk(KERN_ERR __FILE__ ": "
0350             "Error while probing of_platform bus\n");
0351 }
0352 
0353 #define DEFAULT_FIFO_SIZE 16
0354 
0355 const char *__init mpc512x_select_psc_compat(void)
0356 {
0357     if (of_machine_is_compatible("fsl,mpc5121"))
0358         return "fsl,mpc5121-psc";
0359 
0360     if (of_machine_is_compatible("fsl,mpc5125"))
0361         return "fsl,mpc5125-psc";
0362 
0363     return NULL;
0364 }
0365 
0366 const char *__init mpc512x_select_reset_compat(void)
0367 {
0368     if (of_machine_is_compatible("fsl,mpc5121"))
0369         return "fsl,mpc5121-reset";
0370 
0371     if (of_machine_is_compatible("fsl,mpc5125"))
0372         return "fsl,mpc5125-reset";
0373 
0374     return NULL;
0375 }
0376 
0377 static unsigned int __init get_fifo_size(struct device_node *np,
0378                      char *prop_name)
0379 {
0380     const unsigned int *fp;
0381 
0382     fp = of_get_property(np, prop_name, NULL);
0383     if (fp)
0384         return *fp;
0385 
0386     pr_warn("no %s property in %pOF node, defaulting to %d\n",
0387         prop_name, np, DEFAULT_FIFO_SIZE);
0388 
0389     return DEFAULT_FIFO_SIZE;
0390 }
0391 
0392 #define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
0393             ((u32)(_base) + sizeof(struct mpc52xx_psc)))
0394 
0395 /* Init PSC FIFO space for TX and RX slices */
0396 static void __init mpc512x_psc_fifo_init(void)
0397 {
0398     struct device_node *np;
0399     void __iomem *psc;
0400     unsigned int tx_fifo_size;
0401     unsigned int rx_fifo_size;
0402     const char *psc_compat;
0403     int fifobase = 0; /* current fifo address in 32 bit words */
0404 
0405     psc_compat = mpc512x_select_psc_compat();
0406     if (!psc_compat) {
0407         pr_err("%s: no compatible devices found\n", __func__);
0408         return;
0409     }
0410 
0411     for_each_compatible_node(np, NULL, psc_compat) {
0412         tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
0413         rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
0414 
0415         /* size in register is in 4 byte units */
0416         tx_fifo_size /= 4;
0417         rx_fifo_size /= 4;
0418         if (!tx_fifo_size)
0419             tx_fifo_size = 1;
0420         if (!rx_fifo_size)
0421             rx_fifo_size = 1;
0422 
0423         psc = of_iomap(np, 0);
0424         if (!psc) {
0425             pr_err("%s: Can't map %pOF device\n",
0426                 __func__, np);
0427             continue;
0428         }
0429 
0430         /* FIFO space is 4KiB, check if requested size is available */
0431         if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
0432             pr_err("%s: no fifo space available for %pOF\n",
0433                 __func__, np);
0434             iounmap(psc);
0435             /*
0436              * chances are that another device requests less
0437              * fifo space, so we continue.
0438              */
0439             continue;
0440         }
0441 
0442         /* set tx and rx fifo size registers */
0443         out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
0444         fifobase += tx_fifo_size;
0445         out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
0446         fifobase += rx_fifo_size;
0447 
0448         /* reset and enable the slices */
0449         out_be32(&FIFOC(psc)->txcmd, 0x80);
0450         out_be32(&FIFOC(psc)->txcmd, 0x01);
0451         out_be32(&FIFOC(psc)->rxcmd, 0x80);
0452         out_be32(&FIFOC(psc)->rxcmd, 0x01);
0453 
0454         iounmap(psc);
0455     }
0456 }
0457 
0458 void __init mpc512x_init_early(void)
0459 {
0460     mpc512x_restart_init();
0461     if (IS_ENABLED(CONFIG_FB_FSL_DIU))
0462         mpc512x_init_diu();
0463 }
0464 
0465 void __init mpc512x_init(void)
0466 {
0467     mpc5121_clk_init();
0468     mpc512x_declare_of_platform_devices();
0469     mpc512x_psc_fifo_init();
0470 }
0471 
0472 void __init mpc512x_setup_arch(void)
0473 {
0474     if (IS_ENABLED(CONFIG_FB_FSL_DIU))
0475         mpc512x_setup_diu();
0476 }
0477 
0478 /**
0479  * mpc512x_cs_config - Setup chip select configuration
0480  * @cs: chip select number
0481  * @val: chip select configuration value
0482  *
0483  * Perform chip select configuration for devices on LocalPlus Bus.
0484  * Intended to dynamically reconfigure the chip select parameters
0485  * for configurable devices on the bus.
0486  */
0487 int mpc512x_cs_config(unsigned int cs, u32 val)
0488 {
0489     static struct mpc512x_lpc __iomem *lpc;
0490     struct device_node *np;
0491 
0492     if (cs > 7)
0493         return -EINVAL;
0494 
0495     if (!lpc) {
0496         np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-lpc");
0497         lpc = of_iomap(np, 0);
0498         of_node_put(np);
0499         if (!lpc)
0500             return -ENOMEM;
0501     }
0502 
0503     out_be32(&lpc->cs_cfg[cs], val);
0504     return 0;
0505 }
0506 EXPORT_SYMBOL(mpc512x_cs_config);