1ea2305f6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2fb180322SJohn Rigby /* 3fb180322SJohn Rigby * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. 4fb180322SJohn Rigby * 5fb180322SJohn Rigby * Author: John Rigby <jrigby@freescale.com> 6fb180322SJohn Rigby * 7fb180322SJohn Rigby * Description: 8fb180322SJohn Rigby * MPC512x Shared code 9fb180322SJohn Rigby */ 10fb180322SJohn Rigby 11ba218127SGerhard Sittig #include <linux/clk.h> 12fb180322SJohn Rigby #include <linux/kernel.h> 13fb180322SJohn Rigby #include <linux/io.h> 14fb180322SJohn Rigby #include <linux/irq.h> 15fb180322SJohn Rigby #include <linux/of_platform.h> 164b5006ecSAnatolij Gustschin #include <linux/fsl-diu-fb.h> 1710239733SAnton Blanchard #include <linux/memblock.h> 184b5006ecSAnatolij Gustschin #include <sysdev/fsl_soc.h> 19fb180322SJohn Rigby 204b5006ecSAnatolij Gustschin #include <asm/cacheflush.h> 21fb180322SJohn Rigby #include <asm/machdep.h> 22fb180322SJohn Rigby #include <asm/ipic.h> 23fb180322SJohn Rigby #include <asm/prom.h> 24fb180322SJohn Rigby #include <asm/time.h> 25a8dbceb7SAnatolij Gustschin #include <asm/mpc5121.h> 262da8cb6aSAnatolij Gustschin #include <asm/mpc52xx_psc.h> 27fb180322SJohn Rigby 28fb180322SJohn Rigby #include "mpc512x.h" 29fb180322SJohn Rigby 30a8dbceb7SAnatolij Gustschin static struct mpc512x_reset_module __iomem *reset_module_base; 31a8dbceb7SAnatolij Gustschin 32a8dbceb7SAnatolij Gustschin static void __init mpc512x_restart_init(void) 33a8dbceb7SAnatolij Gustschin { 34a8dbceb7SAnatolij Gustschin struct device_node *np; 350875a88eSMatteo Facchinetti const char *reset_compat; 36a8dbceb7SAnatolij Gustschin 370875a88eSMatteo Facchinetti reset_compat = mpc512x_select_reset_compat(); 380875a88eSMatteo Facchinetti np = of_find_compatible_node(NULL, NULL, reset_compat); 39a8dbceb7SAnatolij Gustschin if (!np) 40a8dbceb7SAnatolij Gustschin return; 41a8dbceb7SAnatolij Gustschin 42a8dbceb7SAnatolij Gustschin reset_module_base = of_iomap(np, 0); 43a8dbceb7SAnatolij Gustschin of_node_put(np); 44a8dbceb7SAnatolij Gustschin } 45a8dbceb7SAnatolij Gustschin 4695ec77c0SDaniel Axtens void __noreturn mpc512x_restart(char *cmd) 47a8dbceb7SAnatolij Gustschin { 48a8dbceb7SAnatolij Gustschin if (reset_module_base) { 49a8dbceb7SAnatolij Gustschin /* Enable software reset "RSTE" */ 50a8dbceb7SAnatolij Gustschin out_be32(&reset_module_base->rpr, 0x52535445); 51a8dbceb7SAnatolij Gustschin /* Set software hard reset */ 52a8dbceb7SAnatolij Gustschin out_be32(&reset_module_base->rcr, 0x2); 53a8dbceb7SAnatolij Gustschin } else { 54a8dbceb7SAnatolij Gustschin pr_err("Restart module not mapped.\n"); 55a8dbceb7SAnatolij Gustschin } 56a8dbceb7SAnatolij Gustschin for (;;) 57a8dbceb7SAnatolij Gustschin ; 58a8dbceb7SAnatolij Gustschin } 59a8dbceb7SAnatolij Gustschin 604b5006ecSAnatolij Gustschin struct fsl_diu_shared_fb { 614b5006ecSAnatolij Gustschin u8 gamma[0x300]; /* 32-bit aligned! */ 624b5006ecSAnatolij Gustschin struct diu_ad ad0; /* 32-bit aligned! */ 634b5006ecSAnatolij Gustschin phys_addr_t fb_phys; 644b5006ecSAnatolij Gustschin size_t fb_len; 654b5006ecSAnatolij Gustschin bool in_use; 664b5006ecSAnatolij Gustschin }; 674b5006ecSAnatolij Gustschin 68ba218127SGerhard Sittig /* receives a pixel clock spec in pico seconds, adjusts the DIU clock rate */ 697e198197SBrian Norris static void mpc512x_set_pixel_clock(unsigned int pixclock) 704b5006ecSAnatolij Gustschin { 714b5006ecSAnatolij Gustschin struct device_node *np; 72ba218127SGerhard Sittig struct clk *clk_diu; 73ba218127SGerhard Sittig unsigned long epsilon, minpixclock, maxpixclock; 74ba218127SGerhard Sittig unsigned long offset, want, got, delta; 754b5006ecSAnatolij Gustschin 76ba218127SGerhard Sittig /* lookup and enable the DIU clock */ 77ba218127SGerhard Sittig np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu"); 784b5006ecSAnatolij Gustschin if (!np) { 79ba218127SGerhard Sittig pr_err("Could not find DIU device tree node.\n"); 804b5006ecSAnatolij Gustschin return; 814b5006ecSAnatolij Gustschin } 82ba218127SGerhard Sittig clk_diu = of_clk_get(np, 0); 83ba218127SGerhard Sittig if (IS_ERR(clk_diu)) { 84ba218127SGerhard Sittig /* backwards compat with device trees that lack clock specs */ 85ba218127SGerhard Sittig clk_diu = clk_get_sys(np->name, "ipg"); 86ba218127SGerhard Sittig } 874b5006ecSAnatolij Gustschin of_node_put(np); 88ba218127SGerhard Sittig if (IS_ERR(clk_diu)) { 89ba218127SGerhard Sittig pr_err("Could not lookup DIU clock.\n"); 90ba218127SGerhard Sittig return; 91ba218127SGerhard Sittig } 92ba218127SGerhard Sittig if (clk_prepare_enable(clk_diu)) { 93ba218127SGerhard Sittig pr_err("Could not enable DIU clock.\n"); 944b5006ecSAnatolij Gustschin return; 954b5006ecSAnatolij Gustschin } 964b5006ecSAnatolij Gustschin 97ba218127SGerhard Sittig /* 98ba218127SGerhard Sittig * convert the picoseconds spec into the desired clock rate, 99ba218127SGerhard Sittig * determine the acceptable clock range for the monitor (+/- 5%), 100ba218127SGerhard Sittig * do the calculation in steps to avoid integer overflow 101ba218127SGerhard Sittig */ 102ba218127SGerhard Sittig pr_debug("DIU pixclock in ps - %u\n", pixclock); 103ba218127SGerhard Sittig pixclock = (1000000000 / pixclock) * 1000; 1044b5006ecSAnatolij Gustschin pr_debug("DIU pixclock freq - %u\n", pixclock); 105ba218127SGerhard Sittig epsilon = pixclock / 20; /* pixclock * 0.05 */ 106ba218127SGerhard Sittig pr_debug("DIU deviation - %lu\n", epsilon); 107ba218127SGerhard Sittig minpixclock = pixclock - epsilon; 108ba218127SGerhard Sittig maxpixclock = pixclock + epsilon; 1094b5006ecSAnatolij Gustschin pr_debug("DIU minpixclock - %lu\n", minpixclock); 1104b5006ecSAnatolij Gustschin pr_debug("DIU maxpixclock - %lu\n", maxpixclock); 1114b5006ecSAnatolij Gustschin 112ba218127SGerhard Sittig /* 113ba218127SGerhard Sittig * check whether the DIU supports the desired pixel clock 114ba218127SGerhard Sittig * 115ba218127SGerhard Sittig * - simply request the desired clock and see what the 116ba218127SGerhard Sittig * platform's clock driver will make of it, assuming that it 117ba218127SGerhard Sittig * will setup the best approximation of the requested value 118ba218127SGerhard Sittig * - try other candidate frequencies in the order of decreasing 119ba218127SGerhard Sittig * preference (i.e. with increasing distance from the desired 120ba218127SGerhard Sittig * pixel clock, and checking the lower frequency before the 121ba218127SGerhard Sittig * higher frequency to not overload the hardware) until the 122ba218127SGerhard Sittig * first match is found -- any potential subsequent match 123ba218127SGerhard Sittig * would only be as good as the former match or typically 124ba218127SGerhard Sittig * would be less preferrable 125ba218127SGerhard Sittig * 126ba218127SGerhard Sittig * the offset increment of pixelclock divided by 64 is an 127ba218127SGerhard Sittig * arbitrary choice -- it's simple to calculate, in the typical 128ba218127SGerhard Sittig * case we expect the first check to succeed already, in the 129ba218127SGerhard Sittig * worst case seven frequencies get tested (the exact center and 130ba218127SGerhard Sittig * three more values each to the left and to the right) before 131ba218127SGerhard Sittig * the 5% tolerance window is exceeded, resulting in fast enough 132ba218127SGerhard Sittig * execution yet high enough probability of finding a suitable 133ba218127SGerhard Sittig * value, while the error rate will be in the order of single 134ba218127SGerhard Sittig * percents 135ba218127SGerhard Sittig */ 136ba218127SGerhard Sittig for (offset = 0; offset <= epsilon; offset += pixclock / 64) { 137ba218127SGerhard Sittig want = pixclock - offset; 138ba218127SGerhard Sittig pr_debug("DIU checking clock - %lu\n", want); 139ba218127SGerhard Sittig clk_set_rate(clk_diu, want); 140ba218127SGerhard Sittig got = clk_get_rate(clk_diu); 141ba218127SGerhard Sittig delta = abs(pixclock - got); 142ba218127SGerhard Sittig if (delta < epsilon) 143ba218127SGerhard Sittig break; 144ba218127SGerhard Sittig if (!offset) 145ba218127SGerhard Sittig continue; 146ba218127SGerhard Sittig want = pixclock + offset; 147ba218127SGerhard Sittig pr_debug("DIU checking clock - %lu\n", want); 148ba218127SGerhard Sittig clk_set_rate(clk_diu, want); 149ba218127SGerhard Sittig got = clk_get_rate(clk_diu); 150ba218127SGerhard Sittig delta = abs(pixclock - got); 151ba218127SGerhard Sittig if (delta < epsilon) 152ba218127SGerhard Sittig break; 1534b5006ecSAnatolij Gustschin } 154ba218127SGerhard Sittig if (offset <= epsilon) { 155ba218127SGerhard Sittig pr_debug("DIU clock accepted - %lu\n", want); 156ba218127SGerhard Sittig pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n", 157ba218127SGerhard Sittig pixclock, got, delta, epsilon); 158ba218127SGerhard Sittig return; 1594b5006ecSAnatolij Gustschin } 160ba218127SGerhard Sittig pr_warn("DIU pixclock auto search unsuccessful\n"); 1614b5006ecSAnatolij Gustschin 162ba218127SGerhard Sittig /* 163ba218127SGerhard Sittig * what is the most appropriate action to take when the search 164ba218127SGerhard Sittig * for an available pixel clock which is acceptable to the 165ba218127SGerhard Sittig * monitor has failed? disable the DIU (clock) or just provide 166ba218127SGerhard Sittig * a "best effort"? we go with the latter 167ba218127SGerhard Sittig */ 168ba218127SGerhard Sittig pr_warn("DIU pixclock best effort fallback (backend's choice)\n"); 169ba218127SGerhard Sittig clk_set_rate(clk_diu, pixclock); 170ba218127SGerhard Sittig got = clk_get_rate(clk_diu); 171ba218127SGerhard Sittig delta = abs(pixclock - got); 172ba218127SGerhard Sittig pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n", 173ba218127SGerhard Sittig pixclock, got, delta, epsilon); 1744b5006ecSAnatolij Gustschin } 1754b5006ecSAnatolij Gustschin 1767e198197SBrian Norris static enum fsl_diu_monitor_port 1777653aaabSTimur Tabi mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port) 1784b5006ecSAnatolij Gustschin { 1797653aaabSTimur Tabi return FSL_DIU_PORT_DVI; 1804b5006ecSAnatolij Gustschin } 1814b5006ecSAnatolij Gustschin 1824b5006ecSAnatolij Gustschin static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb; 1834b5006ecSAnatolij Gustschin 1844b5006ecSAnatolij Gustschin static inline void mpc512x_free_bootmem(struct page *page) 1854b5006ecSAnatolij Gustschin { 1864b5006ecSAnatolij Gustschin BUG_ON(PageTail(page)); 187fe896d18SJoonsoo Kim BUG_ON(page_ref_count(page) > 1); 1885d585e5cSJiang Liu free_reserved_page(page); 1894b5006ecSAnatolij Gustschin } 1904b5006ecSAnatolij Gustschin 1917e198197SBrian Norris static void mpc512x_release_bootmem(void) 1924b5006ecSAnatolij Gustschin { 1934b5006ecSAnatolij Gustschin unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK; 1944b5006ecSAnatolij Gustschin unsigned long size = diu_shared_fb.fb_len; 1954b5006ecSAnatolij Gustschin unsigned long start, end; 1964b5006ecSAnatolij Gustschin 1974b5006ecSAnatolij Gustschin if (diu_shared_fb.in_use) { 1984b5006ecSAnatolij Gustschin start = PFN_UP(addr); 1994b5006ecSAnatolij Gustschin end = PFN_DOWN(addr + size); 2004b5006ecSAnatolij Gustschin 2014b5006ecSAnatolij Gustschin for (; start < end; start++) 2024b5006ecSAnatolij Gustschin mpc512x_free_bootmem(pfn_to_page(start)); 2034b5006ecSAnatolij Gustschin 2044b5006ecSAnatolij Gustschin diu_shared_fb.in_use = false; 2054b5006ecSAnatolij Gustschin } 2064b5006ecSAnatolij Gustschin diu_ops.release_bootmem = NULL; 2074b5006ecSAnatolij Gustschin } 2084b5006ecSAnatolij Gustschin 2094b5006ecSAnatolij Gustschin /* 2104b5006ecSAnatolij Gustschin * Check if DIU was pre-initialized. If so, perform steps 2114b5006ecSAnatolij Gustschin * needed to continue displaying through the whole boot process. 2124b5006ecSAnatolij Gustschin * Move area descriptor and gamma table elsewhere, they are 2134b5006ecSAnatolij Gustschin * destroyed by bootmem allocator otherwise. The frame buffer 2144b5006ecSAnatolij Gustschin * address range will be reserved in setup_arch() after bootmem 2154b5006ecSAnatolij Gustschin * allocator is up. 2164b5006ecSAnatolij Gustschin */ 2177e198197SBrian Norris static void __init mpc512x_init_diu(void) 2184b5006ecSAnatolij Gustschin { 2194b5006ecSAnatolij Gustschin struct device_node *np; 2204b5006ecSAnatolij Gustschin struct diu __iomem *diu_reg; 2214b5006ecSAnatolij Gustschin phys_addr_t desc; 2224b5006ecSAnatolij Gustschin void __iomem *vaddr; 2234b5006ecSAnatolij Gustschin unsigned long mode, pix_fmt, res, bpp; 2244b5006ecSAnatolij Gustschin unsigned long dst; 2254b5006ecSAnatolij Gustschin 2264b5006ecSAnatolij Gustschin np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu"); 2274b5006ecSAnatolij Gustschin if (!np) { 2284b5006ecSAnatolij Gustschin pr_err("No DIU node\n"); 2294b5006ecSAnatolij Gustschin return; 2304b5006ecSAnatolij Gustschin } 2314b5006ecSAnatolij Gustschin 2324b5006ecSAnatolij Gustschin diu_reg = of_iomap(np, 0); 2334b5006ecSAnatolij Gustschin of_node_put(np); 2344b5006ecSAnatolij Gustschin if (!diu_reg) { 2354b5006ecSAnatolij Gustschin pr_err("Can't map DIU\n"); 2364b5006ecSAnatolij Gustschin return; 2374b5006ecSAnatolij Gustschin } 2384b5006ecSAnatolij Gustschin 2394b5006ecSAnatolij Gustschin mode = in_be32(&diu_reg->diu_mode); 240c4e5a023STimur Tabi if (mode == MFB_MODE0) { 2414b5006ecSAnatolij Gustschin pr_info("%s: DIU OFF\n", __func__); 2424b5006ecSAnatolij Gustschin goto out; 2434b5006ecSAnatolij Gustschin } 2444b5006ecSAnatolij Gustschin 2454b5006ecSAnatolij Gustschin desc = in_be32(&diu_reg->desc[0]); 2464b5006ecSAnatolij Gustschin vaddr = ioremap(desc, sizeof(struct diu_ad)); 2474b5006ecSAnatolij Gustschin if (!vaddr) { 2484b5006ecSAnatolij Gustschin pr_err("Can't map DIU area desc.\n"); 2494b5006ecSAnatolij Gustschin goto out; 2504b5006ecSAnatolij Gustschin } 2514b5006ecSAnatolij Gustschin memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad)); 2524b5006ecSAnatolij Gustschin /* flush fb area descriptor */ 2534b5006ecSAnatolij Gustschin dst = (unsigned long)&diu_shared_fb.ad0; 2544b5006ecSAnatolij Gustschin flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1); 2554b5006ecSAnatolij Gustschin 2564b5006ecSAnatolij Gustschin res = in_be32(&diu_reg->disp_size); 2574b5006ecSAnatolij Gustschin pix_fmt = in_le32(vaddr); 2584b5006ecSAnatolij Gustschin bpp = ((pix_fmt >> 16) & 0x3) + 1; 2594b5006ecSAnatolij Gustschin diu_shared_fb.fb_phys = in_le32(vaddr + 4); 2604b5006ecSAnatolij Gustschin diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp; 2614b5006ecSAnatolij Gustschin diu_shared_fb.in_use = true; 2624b5006ecSAnatolij Gustschin iounmap(vaddr); 2634b5006ecSAnatolij Gustschin 2644b5006ecSAnatolij Gustschin desc = in_be32(&diu_reg->gamma); 2654b5006ecSAnatolij Gustschin vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma)); 2664b5006ecSAnatolij Gustschin if (!vaddr) { 2674b5006ecSAnatolij Gustschin pr_err("Can't map DIU area desc.\n"); 2684b5006ecSAnatolij Gustschin diu_shared_fb.in_use = false; 2694b5006ecSAnatolij Gustschin goto out; 2704b5006ecSAnatolij Gustschin } 2714b5006ecSAnatolij Gustschin memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma)); 2724b5006ecSAnatolij Gustschin /* flush gamma table */ 2734b5006ecSAnatolij Gustschin dst = (unsigned long)&diu_shared_fb.gamma; 2744b5006ecSAnatolij Gustschin flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1); 2754b5006ecSAnatolij Gustschin 2764b5006ecSAnatolij Gustschin iounmap(vaddr); 2774b5006ecSAnatolij Gustschin out_be32(&diu_reg->gamma, virt_to_phys(&diu_shared_fb.gamma)); 2784b5006ecSAnatolij Gustschin out_be32(&diu_reg->desc[1], 0); 2794b5006ecSAnatolij Gustschin out_be32(&diu_reg->desc[2], 0); 2804b5006ecSAnatolij Gustschin out_be32(&diu_reg->desc[0], virt_to_phys(&diu_shared_fb.ad0)); 2814b5006ecSAnatolij Gustschin 2824b5006ecSAnatolij Gustschin out: 2834b5006ecSAnatolij Gustschin iounmap(diu_reg); 2844b5006ecSAnatolij Gustschin } 2854b5006ecSAnatolij Gustschin 2867e198197SBrian Norris static void __init mpc512x_setup_diu(void) 2874b5006ecSAnatolij Gustschin { 2884b5006ecSAnatolij Gustschin int ret; 2894b5006ecSAnatolij Gustschin 2904b5006ecSAnatolij Gustschin /* 2914b5006ecSAnatolij Gustschin * We do not allocate and configure new area for bitmap buffer 2924b5006ecSAnatolij Gustschin * because it would requere copying bitmap data (splash image) 2934b5006ecSAnatolij Gustschin * and so negatively affect boot time. Instead we reserve the 2944b5006ecSAnatolij Gustschin * already configured frame buffer area so that it won't be 2954b5006ecSAnatolij Gustschin * destroyed. The starting address of the area to reserve and 29610239733SAnton Blanchard * also it's length is passed to memblock_reserve(). It will be 2974b5006ecSAnatolij Gustschin * freed later on first open of fbdev, when splash image is not 2984b5006ecSAnatolij Gustschin * needed any more. 2994b5006ecSAnatolij Gustschin */ 3004b5006ecSAnatolij Gustschin if (diu_shared_fb.in_use) { 30110239733SAnton Blanchard ret = memblock_reserve(diu_shared_fb.fb_phys, 30210239733SAnton Blanchard diu_shared_fb.fb_len); 3034b5006ecSAnatolij Gustschin if (ret) { 3044b5006ecSAnatolij Gustschin pr_err("%s: reserve bootmem failed\n", __func__); 3054b5006ecSAnatolij Gustschin diu_shared_fb.in_use = false; 3064b5006ecSAnatolij Gustschin } 3074b5006ecSAnatolij Gustschin } 3084b5006ecSAnatolij Gustschin 3094b5006ecSAnatolij Gustschin diu_ops.set_pixel_clock = mpc512x_set_pixel_clock; 3107653aaabSTimur Tabi diu_ops.valid_monitor_port = mpc512x_valid_monitor_port; 3114b5006ecSAnatolij Gustschin diu_ops.release_bootmem = mpc512x_release_bootmem; 3124b5006ecSAnatolij Gustschin } 3134b5006ecSAnatolij Gustschin 314fb180322SJohn Rigby void __init mpc512x_init_IRQ(void) 315fb180322SJohn Rigby { 316fb180322SJohn Rigby struct device_node *np; 317fb180322SJohn Rigby 318fb180322SJohn Rigby np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ipic"); 319fb180322SJohn Rigby if (!np) 320fb180322SJohn Rigby return; 321fb180322SJohn Rigby 322fb180322SJohn Rigby ipic_init(np, 0); 323fb180322SJohn Rigby of_node_put(np); 324fb180322SJohn Rigby 325fb180322SJohn Rigby /* 326fb180322SJohn Rigby * Initialize the default interrupt mapping priorities, 327fb180322SJohn Rigby * in case the boot rom changed something on us. 328fb180322SJohn Rigby */ 329fb180322SJohn Rigby ipic_set_default_priority(); 330fb180322SJohn Rigby } 331fb180322SJohn Rigby 332fb180322SJohn Rigby /* 333fb180322SJohn Rigby * Nodes to do bus probe on, soc and localbus 334fb180322SJohn Rigby */ 335ce6d73c9SUwe Kleine-König static const struct of_device_id of_bus_ids[] __initconst = { 336fb180322SJohn Rigby { .compatible = "fsl,mpc5121-immr", }, 337fb180322SJohn Rigby { .compatible = "fsl,mpc5121-localbus", }, 338534ada5eSAnatolij Gustschin { .compatible = "fsl,mpc5121-mbx", }, 339534ada5eSAnatolij Gustschin { .compatible = "fsl,mpc5121-nfc", }, 340534ada5eSAnatolij Gustschin { .compatible = "fsl,mpc5121-sram", }, 341534ada5eSAnatolij Gustschin { .compatible = "fsl,mpc5121-pci", }, 342534ada5eSAnatolij Gustschin { .compatible = "gpio-leds", }, 343fb180322SJohn Rigby {}, 344fb180322SJohn Rigby }; 345fb180322SJohn Rigby 3467e198197SBrian Norris static void __init mpc512x_declare_of_platform_devices(void) 347fb180322SJohn Rigby { 348fb180322SJohn Rigby if (of_platform_bus_probe(NULL, of_bus_ids, NULL)) 349fb180322SJohn Rigby printk(KERN_ERR __FILE__ ": " 350fb180322SJohn Rigby "Error while probing of_platform bus\n"); 351fb180322SJohn Rigby } 352fb180322SJohn Rigby 3532da8cb6aSAnatolij Gustschin #define DEFAULT_FIFO_SIZE 16 3542da8cb6aSAnatolij Gustschin 355*2493a242SNick Child const char *__init mpc512x_select_psc_compat(void) 356a9b6aae4SMatteo Facchinetti { 357a9b6aae4SMatteo Facchinetti if (of_machine_is_compatible("fsl,mpc5121")) 358a9b6aae4SMatteo Facchinetti return "fsl,mpc5121-psc"; 359a9b6aae4SMatteo Facchinetti 360a9b6aae4SMatteo Facchinetti if (of_machine_is_compatible("fsl,mpc5125")) 361a9b6aae4SMatteo Facchinetti return "fsl,mpc5125-psc"; 362a9b6aae4SMatteo Facchinetti 363a9b6aae4SMatteo Facchinetti return NULL; 364a9b6aae4SMatteo Facchinetti } 365a9b6aae4SMatteo Facchinetti 366*2493a242SNick Child const char *__init mpc512x_select_reset_compat(void) 3670875a88eSMatteo Facchinetti { 3680875a88eSMatteo Facchinetti if (of_machine_is_compatible("fsl,mpc5121")) 3690875a88eSMatteo Facchinetti return "fsl,mpc5121-reset"; 3700875a88eSMatteo Facchinetti 3710875a88eSMatteo Facchinetti if (of_machine_is_compatible("fsl,mpc5125")) 3720875a88eSMatteo Facchinetti return "fsl,mpc5125-reset"; 3730875a88eSMatteo Facchinetti 3740875a88eSMatteo Facchinetti return NULL; 3750875a88eSMatteo Facchinetti } 3760875a88eSMatteo Facchinetti 3772da8cb6aSAnatolij Gustschin static unsigned int __init get_fifo_size(struct device_node *np, 3782da8cb6aSAnatolij Gustschin char *prop_name) 3792da8cb6aSAnatolij Gustschin { 3802da8cb6aSAnatolij Gustschin const unsigned int *fp; 3812da8cb6aSAnatolij Gustschin 3822da8cb6aSAnatolij Gustschin fp = of_get_property(np, prop_name, NULL); 3832da8cb6aSAnatolij Gustschin if (fp) 3842da8cb6aSAnatolij Gustschin return *fp; 3852da8cb6aSAnatolij Gustschin 386f2c2cbccSJoe Perches pr_warn("no %s property in %pOF node, defaulting to %d\n", 387b7c670d6SRob Herring prop_name, np, DEFAULT_FIFO_SIZE); 3882da8cb6aSAnatolij Gustschin 3892da8cb6aSAnatolij Gustschin return DEFAULT_FIFO_SIZE; 3902da8cb6aSAnatolij Gustschin } 3912da8cb6aSAnatolij Gustschin 3922da8cb6aSAnatolij Gustschin #define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \ 3932da8cb6aSAnatolij Gustschin ((u32)(_base) + sizeof(struct mpc52xx_psc))) 3942da8cb6aSAnatolij Gustschin 3952da8cb6aSAnatolij Gustschin /* Init PSC FIFO space for TX and RX slices */ 3967e198197SBrian Norris static void __init mpc512x_psc_fifo_init(void) 3972da8cb6aSAnatolij Gustschin { 3982da8cb6aSAnatolij Gustschin struct device_node *np; 3992da8cb6aSAnatolij Gustschin void __iomem *psc; 4002da8cb6aSAnatolij Gustschin unsigned int tx_fifo_size; 4012da8cb6aSAnatolij Gustschin unsigned int rx_fifo_size; 402a9b6aae4SMatteo Facchinetti const char *psc_compat; 4032da8cb6aSAnatolij Gustschin int fifobase = 0; /* current fifo address in 32 bit words */ 4042da8cb6aSAnatolij Gustschin 405a9b6aae4SMatteo Facchinetti psc_compat = mpc512x_select_psc_compat(); 406a9b6aae4SMatteo Facchinetti if (!psc_compat) { 407a9b6aae4SMatteo Facchinetti pr_err("%s: no compatible devices found\n", __func__); 408a9b6aae4SMatteo Facchinetti return; 409a9b6aae4SMatteo Facchinetti } 410a9b6aae4SMatteo Facchinetti 411a9b6aae4SMatteo Facchinetti for_each_compatible_node(np, NULL, psc_compat) { 4122da8cb6aSAnatolij Gustschin tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size"); 4132da8cb6aSAnatolij Gustschin rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size"); 4142da8cb6aSAnatolij Gustschin 4152da8cb6aSAnatolij Gustschin /* size in register is in 4 byte units */ 4162da8cb6aSAnatolij Gustschin tx_fifo_size /= 4; 4172da8cb6aSAnatolij Gustschin rx_fifo_size /= 4; 4182da8cb6aSAnatolij Gustschin if (!tx_fifo_size) 4192da8cb6aSAnatolij Gustschin tx_fifo_size = 1; 4202da8cb6aSAnatolij Gustschin if (!rx_fifo_size) 4212da8cb6aSAnatolij Gustschin rx_fifo_size = 1; 4222da8cb6aSAnatolij Gustschin 4232da8cb6aSAnatolij Gustschin psc = of_iomap(np, 0); 4242da8cb6aSAnatolij Gustschin if (!psc) { 425b7c670d6SRob Herring pr_err("%s: Can't map %pOF device\n", 426b7c670d6SRob Herring __func__, np); 4272da8cb6aSAnatolij Gustschin continue; 4282da8cb6aSAnatolij Gustschin } 4292da8cb6aSAnatolij Gustschin 4302da8cb6aSAnatolij Gustschin /* FIFO space is 4KiB, check if requested size is available */ 4312da8cb6aSAnatolij Gustschin if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) { 432b7c670d6SRob Herring pr_err("%s: no fifo space available for %pOF\n", 433b7c670d6SRob Herring __func__, np); 4342da8cb6aSAnatolij Gustschin iounmap(psc); 4352da8cb6aSAnatolij Gustschin /* 4362da8cb6aSAnatolij Gustschin * chances are that another device requests less 4372da8cb6aSAnatolij Gustschin * fifo space, so we continue. 4382da8cb6aSAnatolij Gustschin */ 4392da8cb6aSAnatolij Gustschin continue; 4402da8cb6aSAnatolij Gustschin } 4412da8cb6aSAnatolij Gustschin 4422da8cb6aSAnatolij Gustschin /* set tx and rx fifo size registers */ 4432da8cb6aSAnatolij Gustschin out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size); 4442da8cb6aSAnatolij Gustschin fifobase += tx_fifo_size; 4452da8cb6aSAnatolij Gustschin out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size); 4462da8cb6aSAnatolij Gustschin fifobase += rx_fifo_size; 4472da8cb6aSAnatolij Gustschin 4482da8cb6aSAnatolij Gustschin /* reset and enable the slices */ 4492da8cb6aSAnatolij Gustschin out_be32(&FIFOC(psc)->txcmd, 0x80); 4502da8cb6aSAnatolij Gustschin out_be32(&FIFOC(psc)->txcmd, 0x01); 4512da8cb6aSAnatolij Gustschin out_be32(&FIFOC(psc)->rxcmd, 0x80); 4522da8cb6aSAnatolij Gustschin out_be32(&FIFOC(psc)->rxcmd, 0x01); 4532da8cb6aSAnatolij Gustschin 4542da8cb6aSAnatolij Gustschin iounmap(psc); 4552da8cb6aSAnatolij Gustschin } 4562da8cb6aSAnatolij Gustschin } 4572da8cb6aSAnatolij Gustschin 4582abbbb63SGerhard Sittig void __init mpc512x_init_early(void) 4592abbbb63SGerhard Sittig { 460a4f4124cSGerhard Sittig mpc512x_restart_init(); 4612abbbb63SGerhard Sittig if (IS_ENABLED(CONFIG_FB_FSL_DIU)) 4622abbbb63SGerhard Sittig mpc512x_init_diu(); 4632abbbb63SGerhard Sittig } 4642abbbb63SGerhard Sittig 465284ed66fSAnatolij Gustschin void __init mpc512x_init(void) 466284ed66fSAnatolij Gustschin { 467284ed66fSAnatolij Gustschin mpc5121_clk_init(); 468f29bc0a4SAnatolij Gustschin mpc512x_declare_of_platform_devices(); 4692da8cb6aSAnatolij Gustschin mpc512x_psc_fifo_init(); 470284ed66fSAnatolij Gustschin } 471edfcf33cSAnatolij Gustschin 4722abbbb63SGerhard Sittig void __init mpc512x_setup_arch(void) 4732abbbb63SGerhard Sittig { 4742abbbb63SGerhard Sittig if (IS_ENABLED(CONFIG_FB_FSL_DIU)) 4752abbbb63SGerhard Sittig mpc512x_setup_diu(); 4762abbbb63SGerhard Sittig } 4772abbbb63SGerhard Sittig 478edfcf33cSAnatolij Gustschin /** 479edfcf33cSAnatolij Gustschin * mpc512x_cs_config - Setup chip select configuration 480edfcf33cSAnatolij Gustschin * @cs: chip select number 481edfcf33cSAnatolij Gustschin * @val: chip select configuration value 482edfcf33cSAnatolij Gustschin * 483edfcf33cSAnatolij Gustschin * Perform chip select configuration for devices on LocalPlus Bus. 484edfcf33cSAnatolij Gustschin * Intended to dynamically reconfigure the chip select parameters 485edfcf33cSAnatolij Gustschin * for configurable devices on the bus. 486edfcf33cSAnatolij Gustschin */ 487edfcf33cSAnatolij Gustschin int mpc512x_cs_config(unsigned int cs, u32 val) 488edfcf33cSAnatolij Gustschin { 489edfcf33cSAnatolij Gustschin static struct mpc512x_lpc __iomem *lpc; 490edfcf33cSAnatolij Gustschin struct device_node *np; 491edfcf33cSAnatolij Gustschin 492edfcf33cSAnatolij Gustschin if (cs > 7) 493edfcf33cSAnatolij Gustschin return -EINVAL; 494edfcf33cSAnatolij Gustschin 495edfcf33cSAnatolij Gustschin if (!lpc) { 496edfcf33cSAnatolij Gustschin np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-lpc"); 497edfcf33cSAnatolij Gustschin lpc = of_iomap(np, 0); 498edfcf33cSAnatolij Gustschin of_node_put(np); 499edfcf33cSAnatolij Gustschin if (!lpc) 500edfcf33cSAnatolij Gustschin return -ENOMEM; 501edfcf33cSAnatolij Gustschin } 502edfcf33cSAnatolij Gustschin 503edfcf33cSAnatolij Gustschin out_be32(&lpc->cs_cfg[cs], val); 504edfcf33cSAnatolij Gustschin return 0; 505edfcf33cSAnatolij Gustschin } 506edfcf33cSAnatolij Gustschin EXPORT_SYMBOL(mpc512x_cs_config); 507