static void __init wakeup_secondary(void) { void __iomem *backupram; if (cpu_is_u8500_family() || cpu_is_ux540_family()) backupram = __io_address(U8500_BACKUPRAM0_BASE); else ux500_unknown_soc(); /* * write the address of secondary startup into the backup ram register * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the * backup ram register at offset 0x1FF0, which is what boot rom code * is waiting for. This would wake up the secondary core from WFE */ #define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 __raw_writel(virt_to_phys(u8500_secondary_startup), backupram + UX500_CPU1_JUMPADDR_OFFSET); #define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 __raw_writel(0xA1FEED01, backupram + UX500_CPU1_WAKEMAGIC_OFFSET); /* make sure write buffer is drained */ mb(); }
static int __init init_display_devices(void) { if (cpu_is_u8500_family()) return handle_display_devices(); else return 0; }
/* * FIXME: Should we set up the GPIO domain here? * * The problem is that we cannot put the interrupt resources into the platform * device until the irqdomain has been added. Right now, we set the GIC interrupt * domain from init_irq(), then load the gpio driver from * core_initcall(nmk_gpio_init) and add the platform devices from * arch_initcall(customize_machine). * * This feels fragile because it depends on the gpio device getting probed * _before_ any device uses the gpio interrupts. */ void __init ux500_init_irq(void) { gic_arch_extn.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; irqchip_init(); /* * Init clocks here so that they are available for system timer * initialization. */ if (cpu_is_u8500_family()) { prcmu_early_init(U8500_PRCMU_BASE, SZ_8K - 1); ux500_pm_init(U8500_PRCMU_BASE, SZ_8K - 1); u8500_of_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE, U8500_CLKRST3_BASE, U8500_CLKRST5_BASE, U8500_CLKRST6_BASE); } else if (cpu_is_u9540()) { prcmu_early_init(U8500_PRCMU_BASE, SZ_8K - 1); ux500_pm_init(U8500_PRCMU_BASE, SZ_8K - 1); u9540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE, U8500_CLKRST3_BASE, U8500_CLKRST5_BASE, U8500_CLKRST6_BASE); } else if (cpu_is_u8540()) { prcmu_early_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1); ux500_pm_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1); u8540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE, U8500_CLKRST3_BASE, U8500_CLKRST5_BASE, U8500_CLKRST6_BASE); } }
void __init ux500_timer_init(void) { void __iomem *prcmu_timer_base; void __iomem *tmp_base; struct device_node *np; if (cpu_is_u8500_family() || cpu_is_ux540_family()) prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE); else ux500_unknown_soc(); np = of_find_matching_node(NULL, prcmu_timer_of_match); if (!np) goto dt_fail; tmp_base = of_iomap(np, 0); if (!tmp_base) goto dt_fail; prcmu_timer_base = tmp_base; dt_fail: clksrc_dbx500_prcmu_init(prcmu_timer_base); clocksource_of_init(); }
/* * FIXME: Should we set up the GPIO domain here? * * The problem is that we cannot put the interrupt resources into the platform * device until the irqdomain has been added. Right now, we set the GIC interrupt * domain from init_irq(), then load the gpio driver from * core_initcall(nmk_gpio_init) and add the platform devices from * arch_initcall(customize_machine). * * This feels fragile because it depends on the gpio device getting probed * _before_ any device uses the gpio interrupts. */ void __init ux500_init_irq(void) { struct device_node *np; struct resource r; irqchip_init(); np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu"); of_address_to_resource(np, 0, &r); of_node_put(np); if (!r.start) { pr_err("could not find PRCMU base resource\n"); return; } prcmu_early_init(r.start, r.end-r.start); ux500_pm_init(r.start, r.end-r.start); /* * Init clocks here so that they are available for system timer * initialization. */ if (cpu_is_u8500_family()) u8500_clk_init(); else if (cpu_is_u9540()) u9540_clk_init(); else if (cpu_is_u8540()) u8540_clk_init(); }
static void __iomem *scu_base_addr(void) { if (cpu_is_u8500_family() || cpu_is_ux540_family()) return __io_address(U8500_SCU_BASE); else ux500_unknown_soc(); return NULL; }
/* * FIXME: Should we set up the GPIO domain here? * * The problem is that we cannot put the interrupt resources into the platform * device until the irqdomain has been added. Right now, we set the GIC interrupt * domain from init_irq(), then load the gpio driver from * core_initcall(nmk_gpio_init) and add the platform devices from * arch_initcall(customize_machine). * * This feels fragile because it depends on the gpio device getting probed * _before_ any device uses the gpio interrupts. */ void __init ux500_init_irq(void) { void __iomem *dist_base; void __iomem *cpu_base; gic_arch_extn.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; if (cpu_is_u8500_family() || cpu_is_ux540_family()) { dist_base = __io_address(U8500_GIC_DIST_BASE); cpu_base = __io_address(U8500_GIC_CPU_BASE); } else ux500_unknown_soc(); #ifdef CONFIG_OF if (of_have_populated_dt()) irqchip_init(); else #endif gic_init(0, 29, dist_base, cpu_base); /* * Init clocks here so that they are available for system timer * initialization. */ if (cpu_is_u8500_family()) { prcmu_early_init(U8500_PRCMU_BASE, SZ_8K - 1); ux500_pm_init(U8500_PRCMU_BASE, SZ_8K - 1); u8500_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE, U8500_CLKRST3_BASE, U8500_CLKRST5_BASE, U8500_CLKRST6_BASE); } else if (cpu_is_u9540()) { prcmu_early_init(U8500_PRCMU_BASE, SZ_8K - 1); ux500_pm_init(U8500_PRCMU_BASE, SZ_8K - 1); u8500_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE, U8500_CLKRST3_BASE, U8500_CLKRST5_BASE, U8500_CLKRST6_BASE); } else if (cpu_is_u8540()) { prcmu_early_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1); ux500_pm_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1); u8540_clk_init(); } }
bool ux500_jtag_enabled(void) { #ifdef CONFIG_UX500_DEBUG_NO_LAUTERBACH return false; #else if (cpu_is_u8500_family() || cpu_is_ux540_family()) return (product_config.rt_flags & TEE_RT_FLAGS_JTAG_ENABLED) == TEE_RT_FLAGS_JTAG_ENABLED; return true; #endif }
void __init ux500_timer_init(void) { void __iomem *mtu_timer_base; void __iomem *prcmu_timer_base; void __iomem *tmp_base; struct device_node *np; if (cpu_is_u8500_family() || cpu_is_ux540_family()) { mtu_timer_base = __io_address(U8500_MTU0_BASE); prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE); } else { ux500_unknown_soc(); } /* TODO: Once MTU has been DT:ed place code above into else. */ if (of_have_populated_dt()) { #ifdef CONFIG_OF np = of_find_matching_node(NULL, prcmu_timer_of_match); if (!np) #endif goto dt_fail; tmp_base = of_iomap(np, 0); if (!tmp_base) goto dt_fail; prcmu_timer_base = tmp_base; } dt_fail: /* Doing it the old fashioned way. */ /* * Here we register the timerblocks active in the system. * Localtimers (twd) is started when both cpu is up and running. * MTU register a clocksource, clockevent and sched_clock. * Since the MTU is located in the VAPE power domain * it will be cleared in sleep which makes it unsuitable. * We however need it as a timer tick (clockevent) * during boot to calibrate delay until twd is started. * RTC-RTT have problems as timer tick during boot since it is * depending on delay which is not yet calibrated. RTC-RTT is in the * always-on powerdomain and is used as clockevent instead of twd when * sleeping. * The PRCMU timer 4 register a clocksource and * sched_clock with higher rating then MTU since is always-on. * */ if (!of_have_populated_dt()) nmdk_timer_init(mtu_timer_base, IRQ_MTU0); clksrc_dbx500_prcmu_init(prcmu_timer_base); ux500_twd_init(); }
static int __init ux500_l2x0_init(void) { /* Multiplatform guard */ if (!((cpu_is_u8500_family() || cpu_is_ux540_family()))) return -ENODEV; /* Unlock before init */ ux500_l2x0_unlock(); outer_cache.write_sec = ux500_l2c310_write_sec; l2x0_of_init(0, ~0); return 0; }
static int __init ux500_rtcrtt_init(void) { if (cpu_is_u8500_family() || cpu_is_ux540_family()) { rtc_base = __io_address(U8500_RTC_BASE); } else { pr_err("timer-rtt: Unknown DB Asic!\n"); return -EINVAL; } if (request_irq(IRQ_DB8500_RTC, rtcrtt_interrupt, IRQF_SHARED | IRQF_NO_SUSPEND, "rtc-pl031-timer", rtc_base)) { pr_err("rtc-rtt: failed to register irq\n"); } ux500_rtcrtt_measure_latency(false); return 0; }
static int __init ux500_l2x0_init(void) { u32 aux_val = 0x3e000000; if (cpu_is_u8500_family() || cpu_is_ux540_family()) l2x0_base = __io_address(U8500_L2CC_BASE); else ux500_unknown_soc(); /* Unlock before init */ ux500_l2x0_unlock(); /* DBx540's L2 has 128KB way size */ if (cpu_is_ux540_family()) /* 128KB way size */ aux_val |= (0x4 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT); else /* 64KB way size */ aux_val |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT); /* 64KB way size, 8 way associativity, force WA */ if (of_have_populated_dt()) l2x0_of_init(aux_val, 0xc0000fff); else l2x0_init(l2x0_base, aux_val, 0xc0000fff); /* * We can't disable l2 as we are in non secure mode, currently * this seems be called only during kexec path. So let's * override outer.disable with nasty assignment until we have * some SMI service available. */ outer_cache.disable = NULL; return 0; }
static int __init product_detect(void) { int err; int origin_err; struct tee_operation operation = {0}; struct tee_context context; struct tee_session session; /* Selects trustzone application needed for the job. */ struct tee_uuid static_uuid = { STATIC_TEE_TA_START_LOW, STATIC_TEE_TA_START_MID, STATIC_TEE_TA_START_HIGH, STATIC_TEE_TA_START_CLOCKSEQ, }; err = teec_initialize_context(NULL, &context); if (err) { pr_err("ux500-product: unable to initialize tee context," " err = %d\n", err); err = -EINVAL; goto error0; } err = teec_open_session(&context, &session, &static_uuid, TEEC_LOGIN_PUBLIC, NULL, NULL, &origin_err); if (err) { pr_err("ux500-product: unable to open tee session," " tee error = %d, origin error = %d\n", err, origin_err); err = -EINVAL; goto error1; } memset(&operation, 0, sizeof(struct tee_operation)); if (cpu_is_u8500_family()) { operation.shm[0].buffer = &product_config; operation.shm[0].size = sizeof(product_config); operation.shm[0].flags = TEEC_MEM_OUTPUT; operation.flags = TEEC_MEMREF_0_USED; } else if (cpu_is_ux540_family()) { operation.param[0].tmpref.buffer = &product_config; operation.param[0].tmpref.size = sizeof(product_config); operation.types = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); } else { pr_err("ux500-product: incorrect memref\n"); err = -EINVAL; goto error1; } err = teec_invoke_command(&session, TEE_STA_GET_PRODUCT_CONFIG, &operation, &origin_err); if (err) { pr_err("ux500-product: fetching product settings failed, err=%d", err); err = -EINVAL; goto error1; } switch (product_config.product_id) { case TEE_PRODUCT_ID_8400: pr_info("ux500-product: u8400 detected\n"); break; case TEE_PRODUCT_ID_8500B: pr_info("ux500-product: u8500B detected\n"); break; case TEE_PRODUCT_ID_9500: pr_info("ux500-product: a9500 detected\n"); break; case TEE_PRODUCT_ID_7400: pr_info("ux500-product: u7400 detected\n"); break; case TEE_PRODUCT_ID_8500C: pr_info("ux500-product: u8500C detected\n"); break; case TEE_PRODUCT_ID_8500A: pr_info("ux500-product: u8500A detected\n"); break; case TEE_PRODUCT_ID_8500E: pr_info("ux500-product: u8500E detected\n"); break; case TEE_PRODUCT_ID_8520F: pr_info("ux500-product: u8520F detected\n"); break; case TEE_PRODUCT_ID_8520H: pr_info("ux500-product: u8520H detected\n"); break; case TEE_PRODUCT_ID_9540: pr_info("ux500-product: u9540 detected\n"); break; case TEE_PRODUCT_ID_9500C: pr_info("ux500-product: a9500C detected\n"); break; case TEE_PRODUCT_ID_8500F: pr_info("ux500-product: u8500F detected\n"); break; case TEE_PRODUCT_ID_8540APE: pr_info("ux500-product: u8540APE detected\n"); break; case TEE_PRODUCT_ID_8540XMIP: pr_info("ux500-product: u8540XMIP detected\n"); break; case TEE_PRODUCT_ID_8520E: pr_info("ux500-product: u8520E detected\n"); break; case TEE_PRODUCT_ID_8520J: pr_info("ux500-product: u8520J detected\n"); break; case TEE_PRODUCT_ID_UNKNOWN: default: pr_info("ux500-product: UNKNOWN! (0x%x) detected\n", product_config.product_id); break; } pr_info("ux500-product: JTAG is %s\n", ux500_jtag_enabled() ? "enabled" : "disabled"); error1: (void) teec_finalize_context(&context); error0: return err; }
/* * This function will create the framebuffer for the display that is registered. */ static int display_postregistered_callback(struct notifier_block *nb, unsigned long event, void *dev) { struct mcde_display_device *ddev = dev; u16 width, height; u16 virtual_height; struct fb_info *fbi; #if defined(CONFIG_DISPDEV) || defined(CONFIG_COMPDEV) struct mcde_fb *mfb; #endif if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED) return 0; if (ddev->id < 0 || ddev->id >= MCDE_NR_OF_DISPLAYS) return 0; mcde_dss_get_native_resolution(ddev, &width, &height); if (ddev->id == PRIMARY_DISPLAY_ID) virtual_height = height * 3; else virtual_height = height * 2; #ifndef CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE if (ddev->id == AV8100_DISPLAY_ID) goto out; #endif /* Create frame buffer */ #if defined(CONFIG_MCDE_DISPLAY_BAMBOOK) fbi = mcde_fb_create(ddev, width, height, width, virtual_height, ddev->default_pixel_format, FB_ROTATE_UD); #else fbi = mcde_fb_create(ddev, width, height, width, virtual_height, ddev->default_pixel_format, FB_ROTATE_UR); #endif if (IS_ERR(fbi)) { dev_warn(&ddev->dev, "Failed to create fb for display %s\n", ddev->name); goto display_postregistered_callback_err; } else { dev_info(&ddev->dev, "Framebuffer created (%s)\n", ddev->name); } #ifdef CONFIG_DISPDEV mfb = to_mcde_fb(fbi); /* Create a dispdev overlay for this display */ if (dispdev_create(ddev, true, mfb->ovlys[0]) < 0) { dev_warn(&ddev->dev, "Failed to create disp for display %s\n", ddev->name); goto display_postregistered_callback_err; } else { dev_info(&ddev->dev, "Disp dev created for (%s)\n", ddev->name); } #endif #ifdef CONFIG_COMPDEV /* Only create compdev for the main display */ if (ddev->id == PRIMARY_DISPLAY_ID) { bool mcde_rotation = false; /* Use mcde rotation for U8500 only */ if (cpu_is_u8500_family()) mcde_rotation = true; mfb = to_mcde_fb(fbi); /* Create a compdev overlay for this display */ if (compdev_create(ddev, mfb->ovlys[0], mcde_rotation, NULL) < 0) { dev_warn(&ddev->dev, "Failed to create compdev for display %s\n", ddev->name); goto display_postregistered_callback_err; } else { dev_info(&ddev->dev, "compdev created for (%s)\n", ddev->name); } } #endif out: return 0; display_postregistered_callback_err: return -1; }