/* SPDX-License-Identifier: GPL-2.0-or-later */1/*2* Copyright (C) 2013 Imagination Technologies3* Author: Paul Burton <[email protected]>4*/56#include <linux/init.h>7#include <asm/addrspace.h>8#include <asm/asm.h>9#include <asm/asm-offsets.h>10#include <asm/asmmacro.h>11#include <asm/cacheops.h>12#include <asm/eva.h>13#include <asm/mipsregs.h>14#include <asm/mipsmtregs.h>15#include <asm/pm.h>16#include <asm/smp-cps.h>1718#define GCR_CPC_BASE_OFS 0x008819#define GCR_CL_COHERENCE_OFS 0x200820#define GCR_CL_ID_OFS 0x202821#define CM3_GCR_Cx_ID_CLUSTER_SHF 822#define CM3_GCR_Cx_ID_CLUSTER_MSK (0xff << 8)23#define CM3_GCR_Cx_ID_CORENUM_SHF 024#define CM3_GCR_Cx_ID_CORENUM_MSK (0xff << 0)2526#define CPC_CL_VC_STOP_OFS 0x202027#define CPC_CL_VC_RUN_OFS 0x20282829.extern mips_cm_base3031.set noreorder3233#ifdef CONFIG_64BIT34# define STATUS_BITDEPS ST0_KX35#else36# define STATUS_BITDEPS 037#endif3839#ifdef CONFIG_MIPS_CPS_NS165504041#define DUMP_EXCEP(name) \42PTR_LA a0, 8f; \43jal mips_cps_bev_dump; \44nop; \45TEXT(name)4647#else /* !CONFIG_MIPS_CPS_NS16550 */4849#define DUMP_EXCEP(name)5051#endif /* !CONFIG_MIPS_CPS_NS16550 */5253/*54* Set dest to non-zero if the core supports the MT ASE, else zero. If55* MT is not supported then branch to nomt.56*/57.macro has_mt dest, nomt58mfc0 \dest, CP0_CONFIG, 159bgez \dest, \nomt60mfc0 \dest, CP0_CONFIG, 261bgez \dest, \nomt62mfc0 \dest, CP0_CONFIG, 363andi \dest, \dest, MIPS_CONF3_MT64beqz \dest, \nomt65nop66.endm6768/*69* Set dest to non-zero if the core supports MIPSr6 multithreading70* (ie. VPs), else zero. If MIPSr6 multithreading is not supported then71* branch to nomt.72*/73.macro has_vp dest, nomt74mfc0 \dest, CP0_CONFIG, 175bgez \dest, \nomt76mfc0 \dest, CP0_CONFIG, 277bgez \dest, \nomt78mfc0 \dest, CP0_CONFIG, 379bgez \dest, \nomt80mfc0 \dest, CP0_CONFIG, 481bgez \dest, \nomt82mfc0 \dest, CP0_CONFIG, 583andi \dest, \dest, MIPS_CONF5_VP84beqz \dest, \nomt85nop86.endm878889LEAF(mips_cps_core_boot)90/* Save CCA and GCR base */91move s0, a092move s1, a19394/* We don't know how to do coherence setup on earlier ISA */95#if MIPS_ISA_REV > 096/* Skip cache & coherence setup if we're already coherent */97lw s7, GCR_CL_COHERENCE_OFS(s1)98bnez s7, 1f99nop100101/* Initialize the L1 caches */102jal mips_cps_cache_init103nop104105/* Enter the coherent domain */106li t0, 0xff107sw t0, GCR_CL_COHERENCE_OFS(s1)108ehb109#endif /* MIPS_ISA_REV > 0 */110111/* Set Kseg0 CCA to that in s0 */1121: mfc0 t0, CP0_CONFIG113ori t0, 0x7114xori t0, 0x7115or t0, t0, s0116mtc0 t0, CP0_CONFIG117ehb118119/* Jump to kseg0 */120PTR_LA t0, 1f121jr t0122nop123124/*125* We're up, cached & coherent. Perform any EVA initialization necessary126* before we access memory.127*/1281: eva_init129130/* Retrieve boot configuration pointers */131jal mips_cps_get_bootcfg132nop133134/* Skip core-level init if we started up coherent */135bnez s7, 1f136nop137138/* Perform any further required core-level initialisation */139jal mips_cps_core_init140nop141142/*143* Boot any other VPEs within this core that should be online, and144* deactivate this VPE if it should be offline.145*/146move a1, t9147jal mips_cps_boot_vpes148move a0, v0149150/* Off we go! */1511: PTR_L t1, VPEBOOTCFG_PC(v1)152PTR_L gp, VPEBOOTCFG_GP(v1)153PTR_L sp, VPEBOOTCFG_SP(v1)154jr t1155nop156END(mips_cps_core_boot)157158__INIT159LEAF(excep_tlbfill)160DUMP_EXCEP("TLB Fill")161b .162nop163END(excep_tlbfill)164165LEAF(excep_xtlbfill)166DUMP_EXCEP("XTLB Fill")167b .168nop169END(excep_xtlbfill)170171LEAF(excep_cache)172DUMP_EXCEP("Cache")173b .174nop175END(excep_cache)176177LEAF(excep_genex)178DUMP_EXCEP("General")179b .180nop181END(excep_genex)182183LEAF(excep_intex)184DUMP_EXCEP("Interrupt")185b .186nop187END(excep_intex)188189LEAF(excep_ejtag)190PTR_LA k0, ejtag_debug_handler191jr k0192nop193END(excep_ejtag)194__FINIT195196LEAF(mips_cps_core_init)197#ifdef CONFIG_MIPS_MT_SMP198/* Check that the core implements the MT ASE */199has_mt t0, 3f200201.set push202.set MIPS_ISA_LEVEL_RAW203.set mt204205/* Only allow 1 TC per VPE to execute... */206dmt207208/* ...and for the moment only 1 VPE */209dvpe210PTR_LA t1, 1f211jr.hb t1212nop213214/* Enter VPE configuration state */2151: mfc0 t0, CP0_MVPCONTROL216ori t0, t0, MVPCONTROL_VPC217mtc0 t0, CP0_MVPCONTROL218219/* Retrieve the number of VPEs within the core */220mfc0 t0, CP0_MVPCONF0221srl t0, t0, MVPCONF0_PVPE_SHIFT222andi t0, t0, (MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT)223addiu ta3, t0, 1224225/* If there's only 1, we're done */226beqz t0, 2f227nop228229/* Loop through each VPE within this core */230li ta1, 12312321: /* Operate on the appropriate TC */233mtc0 ta1, CP0_VPECONTROL234ehb235236/* Bind TC to VPE (1:1 TC:VPE mapping) */237mttc0 ta1, CP0_TCBIND238239/* Set exclusive TC, non-active, master */240li t0, VPECONF0_MVP241sll t1, ta1, VPECONF0_XTC_SHIFT242or t0, t0, t1243mttc0 t0, CP0_VPECONF0244245/* Set TC non-active, non-allocatable */246mttc0 zero, CP0_TCSTATUS247248/* Set TC halted */249li t0, TCHALT_H250mttc0 t0, CP0_TCHALT251252/* Next VPE */253addiu ta1, ta1, 1254slt t0, ta1, ta3255bnez t0, 1b256nop257258/* Leave VPE configuration state */2592: mfc0 t0, CP0_MVPCONTROL260xori t0, t0, MVPCONTROL_VPC261mtc0 t0, CP0_MVPCONTROL2622633: .set pop264#endif265jr ra266nop267END(mips_cps_core_init)268269/**270* mips_cps_get_bootcfg() - retrieve boot configuration pointers271*272* Returns: pointer to struct core_boot_config in v0, pointer to273* struct vpe_boot_config in v1, VPE ID in t9274*/275LEAF(mips_cps_get_bootcfg)276/* Calculate a pointer to this cores struct core_boot_config */277PTR_LA v0, mips_cps_cluster_bootcfg278PTR_L v0, 0(v0)279lw t0, GCR_CL_ID_OFS(s1)280#ifdef CONFIG_CPU_MIPSR6281ext t1, t0, CM3_GCR_Cx_ID_CLUSTER_SHF, 8282li t2, CLUSTERBOOTCFG_SIZE283mul t1, t1, t2284PTR_ADDU \285v0, v0, t1286#endif287PTR_L v0, CLUSTERBOOTCFG_CORECONFIG(v0)288andi t0, t0, CM3_GCR_Cx_ID_CORENUM_MSK289li t1, COREBOOTCFG_SIZE290mul t0, t0, t1291PTR_ADDU v0, v0, t0292293/* Calculate this VPEs ID. If the core doesn't support MT use 0 */294li t9, 0295#if defined(CONFIG_CPU_MIPSR6)296has_vp ta2, 1f297298/*299* Assume non-contiguous numbering. Perhaps some day we'll need300* to handle contiguous VP numbering, but no such systems yet301* exist.302*/303mfc0 t9, CP0_GLOBALNUMBER304andi t9, t9, MIPS_GLOBALNUMBER_VP305#elif defined(CONFIG_MIPS_MT_SMP)306has_mt ta2, 1f307308/* Find the number of VPEs present in the core */309mfc0 t1, CP0_MVPCONF0310srl t1, t1, MVPCONF0_PVPE_SHIFT311andi t1, t1, MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT312addiu t1, t1, 1313314/* Calculate a mask for the VPE ID from EBase.CPUNum */315clz t1, t1316li t2, 31317subu t1, t2, t1318li t2, 1319sll t1, t2, t1320addiu t1, t1, -1321322/* Retrieve the VPE ID from EBase.CPUNum */323mfc0 t9, $15, 1324and t9, t9, t1325#endif3263271: /* Calculate a pointer to this VPEs struct vpe_boot_config */328li t1, VPEBOOTCFG_SIZE329mul v1, t9, t1330PTR_L ta3, COREBOOTCFG_VPECONFIG(v0)331PTR_ADDU v1, v1, ta3332333jr ra334nop335END(mips_cps_get_bootcfg)336337LEAF(mips_cps_boot_vpes)338lw ta2, COREBOOTCFG_VPEMASK(a0)339PTR_L ta3, COREBOOTCFG_VPECONFIG(a0)340341#if defined(CONFIG_CPU_MIPSR6)342343has_vp t0, 5f344345/* Find base address of CPC */346PTR_LA t1, mips_gcr_base347PTR_L t1, 0(t1)348PTR_L t1, GCR_CPC_BASE_OFS(t1)349PTR_LI t2, ~0x7fff350and t1, t1, t2351PTR_LI t2, UNCAC_BASE352PTR_ADD t1, t1, t2353354/* Start any other VPs that ought to be running */355PTR_S ta2, CPC_CL_VC_RUN_OFS(t1)356357/* Ensure this VP stops running if it shouldn't be */358not ta2359PTR_S ta2, CPC_CL_VC_STOP_OFS(t1)360ehb361362#elif defined(CONFIG_MIPS_MT)363364/* If the core doesn't support MT then return */365has_mt t0, 5f366367/* Enter VPE configuration state */368.set push369.set MIPS_ISA_LEVEL_RAW370.set mt371dvpe372.set pop373374PTR_LA t1, 1f375jr.hb t1376nop3771: mfc0 t1, CP0_MVPCONTROL378ori t1, t1, MVPCONTROL_VPC379mtc0 t1, CP0_MVPCONTROL380ehb381382/* Loop through each VPE */383move t8, ta2384li ta1, 0385386/* Check whether the VPE should be running. If not, skip it */3871: andi t0, ta2, 1388beqz t0, 2f389nop390391/* Operate on the appropriate TC */392mfc0 t0, CP0_VPECONTROL393ori t0, t0, VPECONTROL_TARGTC394xori t0, t0, VPECONTROL_TARGTC395or t0, t0, ta1396mtc0 t0, CP0_VPECONTROL397ehb398399.set push400.set MIPS_ISA_LEVEL_RAW401.set mt402403/* Skip the VPE if its TC is not halted */404mftc0 t0, CP0_TCHALT405beqz t0, 2f406nop407408/* Calculate a pointer to the VPEs struct vpe_boot_config */409li t0, VPEBOOTCFG_SIZE410mul t0, t0, ta1411PTR_ADDU t0, t0, ta3412413/* Set the TC restart PC */414lw t1, VPEBOOTCFG_PC(t0)415mttc0 t1, CP0_TCRESTART416417/* Set the TC stack pointer */418lw t1, VPEBOOTCFG_SP(t0)419mttgpr t1, sp420421/* Set the TC global pointer */422lw t1, VPEBOOTCFG_GP(t0)423mttgpr t1, gp424425/* Copy config from this VPE */426mfc0 t0, CP0_CONFIG427mttc0 t0, CP0_CONFIG428429/*430* Copy the EVA config from this VPE if the CPU supports it.431* CONFIG3 must exist to be running MT startup - just read it.432*/433mfc0 t0, CP0_CONFIG, 3434and t0, t0, MIPS_CONF3_SC435beqz t0, 3f436nop437mfc0 t0, CP0_SEGCTL0438mttc0 t0, CP0_SEGCTL0439mfc0 t0, CP0_SEGCTL1440mttc0 t0, CP0_SEGCTL1441mfc0 t0, CP0_SEGCTL2442mttc0 t0, CP0_SEGCTL24433:444/* Ensure no software interrupts are pending */445mttc0 zero, CP0_CAUSE446mttc0 zero, CP0_STATUS447448/* Set TC active, not interrupt exempt */449mftc0 t0, CP0_TCSTATUS450li t1, ~TCSTATUS_IXMT451and t0, t0, t1452ori t0, t0, TCSTATUS_A453mttc0 t0, CP0_TCSTATUS454455/* Clear the TC halt bit */456mttc0 zero, CP0_TCHALT457458/* Set VPE active */459mftc0 t0, CP0_VPECONF0460ori t0, t0, VPECONF0_VPA461mttc0 t0, CP0_VPECONF0462463/* Next VPE */4642: srl ta2, ta2, 1465addiu ta1, ta1, 1466bnez ta2, 1b467nop468469/* Leave VPE configuration state */470mfc0 t1, CP0_MVPCONTROL471xori t1, t1, MVPCONTROL_VPC472mtc0 t1, CP0_MVPCONTROL473ehb474evpe475476.set pop477478/* Check whether this VPE is meant to be running */479li t0, 1480sll t0, t0, a1481and t0, t0, t8482bnez t0, 2f483nop484485/* This VPE should be offline, halt the TC */486li t0, TCHALT_H487mtc0 t0, CP0_TCHALT488PTR_LA t0, 1f4891: jr.hb t0490nop4914922:493494#endif /* CONFIG_MIPS_MT_SMP */495496/* Return */4975: jr ra498nop499END(mips_cps_boot_vpes)500501#if MIPS_ISA_REV > 0502LEAF(mips_cps_cache_init)503/*504* Clear the bits used to index the caches. Note that the architecture505* dictates that writing to any of TagLo or TagHi selects 0 or 2 should506* be valid for all MIPS32 CPUs, even those for which said writes are507* unnecessary.508*/509mtc0 zero, CP0_TAGLO, 0510mtc0 zero, CP0_TAGHI, 0511mtc0 zero, CP0_TAGLO, 2512mtc0 zero, CP0_TAGHI, 2513ehb514515/* Primary cache configuration is indicated by Config1 */516mfc0 v0, CP0_CONFIG, 1517518/* Detect I-cache line size */519_EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ520beqz t0, icache_done521li t1, 2522sllv t0, t1, t0523524/* Detect I-cache size */525_EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ526xori t2, t1, 0x7527beqz t2, 1f528li t3, 32529addiu t1, t1, 1530sllv t1, t3, t15311: /* At this point t1 == I-cache sets per way */532_EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ533addiu t2, t2, 1534mul t1, t1, t0535mul t1, t1, t2536537li a0, CKSEG0538PTR_ADD a1, a0, t15391: cache Index_Store_Tag_I, 0(a0)540PTR_ADD a0, a0, t0541bne a0, a1, 1b542nop543icache_done:544545/* Detect D-cache line size */546_EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ547beqz t0, dcache_done548li t1, 2549sllv t0, t1, t0550551/* Detect D-cache size */552_EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ553xori t2, t1, 0x7554beqz t2, 1f555li t3, 32556addiu t1, t1, 1557sllv t1, t3, t15581: /* At this point t1 == D-cache sets per way */559_EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ560addiu t2, t2, 1561mul t1, t1, t0562mul t1, t1, t2563564li a0, CKSEG0565PTR_ADDU a1, a0, t1566PTR_SUBU a1, a1, t05671: cache Index_Store_Tag_D, 0(a0)568bne a0, a1, 1b569PTR_ADD a0, a0, t0570dcache_done:571572jr ra573nop574END(mips_cps_cache_init)575#endif /* MIPS_ISA_REV > 0 */576577#if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM)578579/* Calculate a pointer to this CPUs struct mips_static_suspend_state */580.macro psstate dest581.set push582.set noat583lw $1, TI_CPU(gp)584sll $1, $1, LONGLOG585PTR_LA \dest, __per_cpu_offset586PTR_ADDU $1, $1, \dest587lw $1, 0($1)588PTR_LA \dest, cps_cpu_state589PTR_ADDU \dest, \dest, $1590.set pop591.endm592593LEAF(mips_cps_pm_save)594/* Save CPU state */595SUSPEND_SAVE_REGS596psstate t1597SUSPEND_SAVE_STATIC598jr v0599nop600END(mips_cps_pm_save)601602LEAF(mips_cps_pm_restore)603/* Restore CPU state */604psstate t1605RESUME_RESTORE_STATIC606RESUME_RESTORE_REGS_RETURN607END(mips_cps_pm_restore)608609#endif /* CONFIG_MIPS_CPS_PM && CONFIG_CPU_PM */610611612