From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from loongson.cn (loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web08.3761.1668160035042654744 for ; Fri, 11 Nov 2022 01:47:16 -0800 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: loongson.cn, ip: 114.242.206.163, mailfrom: lichao@loongson.cn) Received: from loongson.cn (unknown [10.40.24.149]) by gateway (Coremail) with SMTP id _____8BxXbciGm5jjxYGAA--.9799S3; Fri, 11 Nov 2022 17:47:14 +0800 (CST) Received: from lichao-PC (unknown [10.40.24.149]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Axf+AhGm5joNMQAA--.46172S2; Fri, 11 Nov 2022 17:47:13 +0800 (CST) Date: Fri, 11 Nov 2022 17:47:13 +0800 From: "Chao Li" To: xianglai li Cc: "=?utf-8?Q?devel=40edk2.groups.io?=" , Bibo Mao , Leif Lindholm , Liming Gao , Michael D Kinney Message-ID: <980F5BE8-A956-43D2-8902-17E66EBFD411@getmailspring.com> In-Reply-To: <020fd4009f60f83db22e30017009b6e4c7ed7636.1668157715.git.lixianglai@loongson.cn> References: <020fd4009f60f83db22e30017009b6e4c7ed7636.1668157715.git.lixianglai@loongson.cn> Subject: Re: [edk2-platforms][PATCH V5 10/15] Platform/Loongson: Add timer Dxe driver. X-Mailer: Mailspring MIME-Version: 1.0 X-CM-TRANSID: AQAAf8Axf+AhGm5joNMQAA--.46172S2 X-CM-SenderInfo: xolfxt3r6o00pqjv00gofq/1tbiAQAHCGNs6eQZ0AAjsm X-Coremail-Antispam: 1Uk129KBjvAXoWfKryrCr1kCF43GFWUCw1rJFb_yoW8tryxto W8uFZFvw18Gr18XaykJFyxJa42qF1kuws0qr4vgFykCFnYy3Z8Kr9Fyry5Kw1fZrWrJFsr A34xWa4kJF43X3Z5n29KB7ZKAUJUUUUk529EdanIXcx71UUUUU7KY7ZEXasCq-sGcSsGvf J3Ec02F40Eb7x2x7xS6r1j6r4UMc02F40EFcxC0VAKzVAqx4xG6I80ewAqx4xG64kEw2xG 04xIwI0_Xr0_WrUv73VFW2AGmfu7bjvjm3AaLaJ3UjIYCTnIWjp_UUUOf7kC6x804xWl14 x267AKxVWUJVW8JwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0rVWrJVCq3wAFIxvE14AKwVWU GVWUXwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK021l84ACjcxK6xIIjxv20xvE14 v26F1j6w1UM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4j6F4UM28EF7xvwVC2z280aVAF wI0_Cr1j6rxdM28EF7xvwVC2z280aVCY1x0267AKxVWxJr0_GcWln4kS14v26r1q6r43M2 AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6xACxx1l5I8CrVAYj202 j2C_Jr0_Gr1l5I8CrVACY4xI64kE6c02F40Ex7xfMc02F40Ew4AK048IF2xKxVW5JVWrJw Av7VC0I7IYx2IY67AKxVWrXVW3AwAv7VC2z280aVAFwI0_Gr0_Cr1lOx8S6xCaFVCjc4AY 6r1j6r4UM4x0Y48IcxkI7VAKI48JMx8GjcxK6IxK0xIIj40E5I8CrwCY1x0262kKe7AKxV WUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E 14v26r106r1rMI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_JF0_Jw1lIx kGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVW7JVWDJwCI42IY6xIIjxv20xvEc7CjxVAF wI0_Gr0_Cr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r4j6F 4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07jHKZXU UUUU= Content-Type: multipart/alternative; boundary="636e1a21_4d25e82c_1e57b" --636e1a21_4d25e82c_1e57b Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Reviewed-by: Chao Li Thanks, Chao -------- On 11=E6=9C=88 11 2022, at 5:12 =E4=B8=8B=E5=8D=88, xianglai li wrote: > This driver produces Timer Architectural Protocol, > > Registers a timer interrupt and initializes the timer. > > > RE=46: https://bugzilla.tianocore.org/show=5Fbug.cgi=3Fid=3D4054 > > > Cc: Bibo Mao > Cc: Chao Li > Cc: Leif Lindholm > Cc: Liming Gao > Cc: Michael D Kinney > Signed-off-by: xianglai li > --- > .../Drivers/StableTimerDxe/Timer.c =7C 388 ++++++++++++++++++ > .../Drivers/StableTimerDxe/Timer.h =7C 172 ++++++++ > .../Drivers/StableTimerDxe/TimerConfig.S =7C 38 ++ > .../Drivers/StableTimerDxe/TimerDxe.inf =7C 44 ++ > 4 files changed, 642 insertions(+) > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTim= erDxe/Timer.c > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTim= erDxe/Timer.h > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTim= erDxe/TimerConfig.S > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTim= erDxe/TimerDxe.inf > > > diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/= Timer.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer= .c > new file mode 100644 > index 0000000000..e09da71272 > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c= > =40=40 -0,0 +1,388 =40=40 > +/** =40file > + Timer Architectural Protocol as defined in the DXE CIS > + > + Copyright (c) 2022 Loongson Technology Corporation Limited. All right= s reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +=23include > +=23include =22Library/Cpu.h=22 > +=23include > +=23include > +=23include =22Timer.h=22 > +=23include > +=23include > + > +// > +// The handle onto which the Timer Architectural Protocol will be inst= alled > +// > +E=46I=5FHANDLE mTimerHandle =3D NULL; > +E=46I=5FEVENT EfiExitBootServicesEvent =3D (E=46I=5FEVENT)NULL; > + > +// > +// The Timer Architectural Protocol that this driver produces > +// > +E=46I=5FTIMER=5FARCH=5FPROTOCOL mTimer =3D =7B > + TimerDriverRegisterHandler, > + TimerDriverSetTimerPeriod, > + TimerDriverGetTimerPeriod, > + TimerDriverGenerateSoftInterrupt > +=7D; > + > +// > +// Pointer to the CPU Architectural Protocol instance > +// > +E=46I=5FCPU=5FARCH=5FPROTOCOL *mCpu; > + > +// > +// The notification function to call on every timer interrupt. > +// A bug in the compiler prevents us from initializing this here. > +// > +E=46I=5FTIMER=5FNOTI=46Y mTimerNotify=46unction; > + > +// > +// The current period of the timer interrupt > +// > +volatile UINT64 mTimerPeriod =3D 0; > +volatile UINT64 mTimerTicks =3D 0; > + > +// > +// Const frequence in Hz > +// > +extern UINT32 StableTimer=46req; > + > +/** > + Sets the counter value for timer. > + > + =40param Count The 16-bit counter value to program into stable timer.= > + > + =40retval VOID > +**/ > +VOID > +SetPitCount ( > + IN UINT64 Count > + ) > +=7B > + if (Count <=3D 4) =7B > + return; > + =7D > + > + Count &=3D LOONGARCH=5FCSR=5FTMC=46G=5FTIMEVAL; > + Count =7C=3D LOONGARCH=5FCSR=5FTMC=46G=5FEN =7C LOONGARCH=5FCSR=5FTMC= =46G=5FPERIOD; > + LoongarchWriteqTmcfg (Count); > +=7D > + > +/** > + Timer Interrupt Handler. > + > + =40param InterruptType The type of interrupt that occurred > + =40param SystemContext A pointer to the system context when the inter= rupt occurred > + > + =40retval VOID > +**/ > +VOID > +E=46IAPI > +TimerInterruptHandler ( > + IN E=46I=5FEXCEPTION=5FTYPE InterruptType, > + IN E=46I=5FSYSTEM=5FCONTEXT SystemContext > + ) > +=7B > + E=46I=5FTPL OriginalTPL; > + > + OriginalTPL =3D gBS->RaiseTPL (TPL=5FHIGH=5FLEVEL); > + > + // > + // Clear interrupt. > + // > + LoongarchWriteqTintclr (0x1); > + > + if (mTimerNotify=46unction =21=3D NULL) =7B > + // > + // =40bug : This does not handle missed timer interrupts > + // > + mTimerNotify=46unction (mTimerPeriod); > + =7D > + > + gBS->RestoreTPL (OriginalTPL); > +=7D > + > +/** > + This function registers the handler Notify=46unction so it is called = every time > + the timer interrupt fires. It also passes the amount of time since th= e last > + handler call to the Notify=46unction. If Notify=46unction is NULL, th= en the > + handler is unregistered. If the handler is registered, then E=46I=5FS= UCCESS is > + returned. If the CPU does not support registering a timer interrupt h= andler, > + then E=46I=5FUNSUPPORTED is returned. If an attempt is made to regist= er a handler > + when a handler is already registered, then E=46I=5FALREADY=5FSTARTED = is returned. > + If an attempt is made to unregister a handler when a handler is not r= egistered, > + then E=46I=5FINVALID=5FPARAMETER is returned. If an error occurs atte= mpting to > + register the Notify=46unction with the timer interrupt, then E=46I=5F= DEVICE=5FERROR > + is returned. > + > + =40param This The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance. > + =40param Notify=46unction The function to call when a timer interrupt= fires. This > + function executes at TPL=5FHIGH=5FLEVEL. The DXE Core will > + register a handler for the timer interrupt, so it can know > + how much time has passed. This information is used to > + signal timer based events. NULL will unregister the handler. > + > + =40retval E=46I=5FSUCCESS The timer handler was registered. > + =40retval E=46I=5FUNSUPPORTED The platform does not support timer int= errupts. > + =40retval E=46I=5FALREADY=5FSTARTED Notify=46unction is not NULL, and= a handler is already > + registered. > + =40retval E=46I=5FINVALID=5FPARAMETER Notify=46unction is NULL, and a= handler was not > + previously registered. > + =40retval E=46I=5FDEVICE=5FERROR The timer handler could not be regis= tered. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +TimerDriverRegisterHandler ( > + IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This, > + IN E=46I=5FTIMER=5FNOTI=46Y Notify=46unction > + ) > +=7B > + // > + // Check for invalid parameters > + // > + if ((Notify=46unction =3D=3D NULL) > + && (mTimerNotify=46unction =3D=3D NULL)) > + =7B > + return E=46I=5FINVALID=5FPARAMETER; > + =7D > + > + if ((Notify=46unction =21=3D NULL) > + && mTimerNotify=46unction =21=3D NULL) > + =7B > + return E=46I=5FALREADY=5FSTARTED; > + =7D > + > + mTimerNotify=46unction =3D Notify=46unction; > + > + return E=46I=5FSUCCESS; > +=7D > + > +/** > + This function adjusts the period of timer interrupts to the value spe= cified > + by TimerPeriod. If the timer period is updated, then the selected tim= er > + period is stored in E=46I=5FTIMER.TimerPeriod, and E=46I=5FSUCCESS is= returned. If > + the timer hardware is not programmable, then E=46I=5FUNSUPPORTED is r= eturned. > + If an error occurs while attempting to update the timer period, then = the > + timer hardware will be put back in its state prior to this call, and > + E=46I=5FDEVICE=5FERROR is returned. If TimerPeriod is 0, then the tim= er interrupt > + is disabled. This is not the same as disabling the CPU's interrupts. > + Instead, it must either turn off the timer hardware, or it must adjus= t the > + interrupt controller so that a CPU interrupt is not generated when th= e timer > + interrupt fires. > + > + =40param This The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance. > + =40param TimerPeriod The rate to program the timer interrupt in 100 n= S units. If > + the timer hardware is not programmable, then E=46I=5FUNSUPPORTED is > + returned. If the timer is programmable, then the timer period > + will be rounded up to the nearest timer period that is supported > + by the timer hardware. If TimerPeriod is set to 0, then the > + timer interrupts will be disabled. > + > + =40retval E=46I=5FSUCCESS The timer period was changed. > + =40retval E=46I=5FUNSUPPORTED The platform cannot change the period o= f the timer interrupt. > + =40retval E=46I=5FDEVICE=5FERROR The timer period could not be change= d due to a device error. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +TimerDriverSetTimerPeriod ( > + IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This, > + IN UINT64 TimerPeriod > + ) > +=7B > + UINT64 TimerCount; > + > + if (TimerPeriod =3D=3D 0) =7B > + // > + // Disable timer interrupt for a TimerPeriod of 0 > + // > + mCpu->DisableInterrupt (mCpu); > + =7D else =7B > + > + TimerCount =3D TimerPeriod * StableTimer=46req / 10000000ULL; > + > + if (TimerCount >=3D BIT48) =7B > + TimerCount =3D 0; > + =7D > + > + // > + // Program the stable timer with the new count value > + // > + mTimerTicks =3D TimerCount; > + SetPitCount (TimerCount); > + > + // > + // Enable timer interrupt > + // > + mCpu->EnableInterrupt (mCpu); > + =7D > + > + // > + // Save the new timer period > + // > + mTimerPeriod =3D TimerPeriod; > + > + return E=46I=5FSUCCESS; > +=7D > + > +/** > + This function retrieves the period of timer interrupts in 100 ns unit= s, > + returns that value in TimerPeriod, and returns E=46I=5FSUCCESS. If Ti= merPeriod > + is NULL, then E=46I=5FINVALID=5FPARAMETER is returned. If a TimerPeri= od of 0 is > + returned, then the timer is currently disabled. > + > + =40param This The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance. > + =40param TimerPeriod A pointer to the timer period to retrieve in 100= ns units. If > + 0 is returned, then the timer is currently disabled. > + > + =40retval E=46I=5FSUCCESS The timer period was returned in TimerPerio= d. > + =40retval E=46I=5FINVALID=5FPARAMETER TimerPeriod is NULL. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +TimerDriverGetTimerPeriod ( > + IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This, > + OUT UINT64 *TimerPeriod > + ) > +=7B > + if (TimerPeriod =3D=3D NULL) =7B > + return E=46I=5FINVALID=5FPARAMETER; > + =7D > + > + *TimerPeriod =3D mTimerPeriod; > + > + return E=46I=5FSUCCESS; > +=7D > + > +/** > + Disable the timer > + DXE Core will disable the timer after all the event handlers have run= . > + > + =40param=5Bin=5D Event The Event that is being processed > + =40param=5Bin=5D Context Event Context > +**/ > +VOID > +E=46IAPI > +ExitBootServicesEvent ( > + IN E=46I=5FEVENT Event, > + IN VOID *Context > + ) > +=7B > + /* > + * Disable timer interrupt when exiting boot service > + */ > + LoongarchWriteqTmcfg (0); > +=7D > + > +/** > + This function generates a soft timer interrupt. If the platform does = not support soft > + timer interrupts, then E=46I=5FUNSUPPORTED is returned. Otherwise, E=46= I=5FSUCCESS is returned. > + If a handler has been registered through the E=46I=5FTIMER=5FARCH=5FP= ROTOCOL.RegisterHandler () > + service, then a soft timer interrupt will be generated. If the timer = interrupt is > + enabled when this service is called, then the registered handler will= be invoked. The > + registered handler should not be able to distinguish a hardware-gener= ated timer > + interrupt from a software-generated timer interrupt. > + > + =40param This The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance. > + > + =40retval E=46I=5FSUCCESS The soft timer interrupt was generated. > + =40retval E=46I=5FUNSUPPORTED The platform does not support the gener= ation of soft timer interrupts. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +TimerDriverGenerateSoftInterrupt ( > + IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This > + ) > +=7B > + return E=46I=5FUNSUPPORTED; > +=7D > + > +/** > + Initialize the Timer Architectural Protocol driver > + > + =40param ImageHandle ImageHandle of the loaded driver > + =40param SystemTable Pointer to the System Table > + > + =40retval E=46I=5FSUCCESS Timer Architectural Protocol created > + =40retval E=46I=5FOUT=5FO=46=5FRESOURCES Not enough resources availab= le to initialize driver. > + =40retval E=46I=5FDEVICE=5FERROR A device error occurred attempting t= o initialize the driver. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +StableTimerDriverInitialize ( > + IN E=46I=5FHANDLE ImageHandle, > + IN E=46I=5FSYSTEM=5FTABLE *SystemTable > + ) > +=7B > + E=46I=5FSTATUS Status; > + UINT32 TimerVector; > + > + // > + // Initialize the pointer to our notify function. > + // > + mTimerNotify=46unction =3D NULL; > + > + // > + // Make sure the Timer Architectural Protocol is not already installe= d in the system > + // > + ASSERT=5FPROTOCOL=5FALREADY=5FINSTALLED (NULL, &gEfiTimerArchProtocol= Guid); > + > + // > + // =46ind the CPU architectural protocol. > + // > + Status =3D gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID= **) &mCpu); > + ASSERT=5FE=46I=5FERROR (Status); > + > + // > + // =46orce the timer to be disabled > + // > + Status =3D TimerDriverSetTimerPeriod (&mTimer, 0); > + ASSERT=5FE=46I=5FERROR (Status); > + > + // > + // Calculate const frequence > + // > + StableTimer=46req =3D CalcConst=46req (); > + DEBUG ((DEBUG=5FIN=46O, =22=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3DStable ti= mer freq %d Hz=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=5Cn=22, StableTimer= =46req)); > + > + // > + // Install interrupt handler for Stable Timer =230 (ISA IRQ0) > + // > + TimerVector =3D EXCEPT=5FLOONGARCH=5FINT=5FTIMER; > + Status =3D mCpu->RegisterInterruptHandler (mCpu, TimerVector, TimerIn= terruptHandler); > + ASSERT=5FE=46I=5FERROR (Status); > + > + // > + // Enable TI local timer interrupt > + // > + CpuSetIP (1 << 11); > + > + // > + // =46orce the timer to be enabled at its default period > + // > + Status =3D TimerDriverSetTimerPeriod (&mTimer, DE=46AULT=5FTIMER=5FTI= CK=5FDURATION); > + ASSERT=5FE=46I=5FERROR (Status); > + > + // > + // Install the Timer Architectural Protocol onto a new handle > + // > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &mTimerHandle, > + &gEfiTimerArchProtocolGuid, &mTimer, > + NULL > + ); > + > + ASSERT=5FE=46I=5FERROR (Status); > + > + // Register for an ExitBootServicesEvent > + Status =3D gBS->CreateEvent (EVT=5FSIGNAL=5FEXIT=5FBOOT=5FSERVICES, T= PL=5FNOTI=46Y, ExitBootServicesEvent, NULL, > + &EfiExitBootServicesEvent); > + ASSERT=5FE=46I=5FERROR (Status); > + > + return Status; > +=7D > diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/= Timer.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer= .h > new file mode 100644 > index 0000000000..84036cab00 > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h= > =40=40 -0,0 +1,172 =40=40 > +/** =40file > + Private data structures > + > + Copyright (c) 2022 Loongson Technology Corporation Limited. All right= s reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +=23ifndef TIMER=5FH=5F > +=23define TIMER=5FH=5F > + > +=23include > + > +=23define DE=46AULT=5FTIMER=5FTICK=5FDURATION 100000 //10ms =3D 100000= 100 ns units > +=23define SR=5FIP7 (1 << 15) > +// > +// =46unction Prototypes > +// > +extern UINT32 E=46IAPI CpuGetCompare(VOID); > +extern VOID E=46IAPI CpuSetCompare(IN UINT32 val); > +extern VOID E=46IAPI CpuSetIP(IN UINT32 val); > +extern VOID E=46IAPI ClearC0Cause(IN UINT32 val); > +extern VOID E=46IAPI ClearC0Status(IN UINT32 val); > +/** > + Initialize the Timer Architectural Protocol driver > + > + =40param ImageHandle ImageHandle of the loaded driver > + =40param SystemTable Pointer to the System Table > + > + =40retval E=46I=5FSUCCESS Timer Architectural Protocol created > + =40retval E=46I=5FOUT=5FO=46=5FRESOURCES Not enough resources availab= le to initialize driver. > + =40retval E=46I=5FDEVICE=5FERROR A device error occurred attempting t= o initialize the driver. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +TimerDriverInitialize ( > + IN E=46I=5FHANDLE ImageHandle, > + IN E=46I=5FSYSTEM=5FTABLE *SystemTable > + ); > + > +/** > + This function adjusts the period of timer interrupts to the value spe= cified > + by TimerPeriod. If the timer period is updated, then the selected tim= er > + period is stored in E=46I=5FTIMER.TimerPeriod, and E=46I=5FSUCCESS is= returned. If > + the timer hardware is not programmable, then E=46I=5FUNSUPPORTED is r= eturned. > + If an error occurs while attempting to update the timer period, then = the > + timer hardware will be put back in its state prior to this call, and > + E=46I=5FDEVICE=5FERROR is returned. If TimerPeriod is 0, then the tim= er interrupt > + is disabled. This is not the same as disabling the CPU's interrupts. > + Instead, it must either turn off the timer hardware, or it must adjus= t the > + interrupt controller so that a CPU interrupt is not generated when th= e timer > + interrupt fires. > + > + =40param This The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance. > + =40param Notify=46unction The rate to program the timer interrupt in = 100 nS units. If > + the timer hardware is not programmable, then E=46I=5FUNSUPPORTED is > + returned. If the timer is programmable, then the timer period > + will be rounded up to the nearest timer period that is supported > + by the timer hardware. If TimerPeriod is set to 0, then the > + timer interrupts will be disabled. > + > + =40retval E=46I=5FSUCCESS The timer period was changed. > + =40retval E=46I=5FUNSUPPORTED The platform cannot change the period o= f the timer interrupt. > + =40retval E=46I=5FDEVICE=5FERROR The timer period could not be change= d due to a device error. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +TimerDriverRegisterHandler ( > + IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This, > + IN E=46I=5FTIMER=5FNOTI=46Y Notify=46unction > + ); > + > +/** > + This function adjusts the period of timer interrupts to the value spe= cified > + by TimerPeriod. If the timer period is updated, then the selected tim= er > + period is stored in E=46I=5FTIMER.TimerPeriod, and E=46I=5FSUCCESS is= returned. If > + the timer hardware is not programmable, then E=46I=5FUNSUPPORTED is r= eturned. > + If an error occurs while attempting to update the timer period, then = the > + timer hardware will be put back in its state prior to this call, and > + E=46I=5FDEVICE=5FERROR is returned. If TimerPeriod is 0, then the tim= er interrupt > + is disabled. This is not the same as disabling the CPU's interrupts. > + Instead, it must either turn off the timer hardware, or it must adjus= t the > + interrupt controller so that a CPU interrupt is not generated when th= e timer > + interrupt fires. > + > + =40param This The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance. > + =40param TimerPeriod The rate to program the timer interrupt in 100 n= S units. If > + the timer hardware is not programmable, then E=46I=5FUNSUPPORTED is > + returned. If the timer is programmable, then the timer period > + will be rounded up to the nearest timer period that is supported > + by the timer hardware. If TimerPeriod is set to 0, then the > + timer interrupts will be disabled. > + > + =40retval E=46I=5FSUCCESS The timer period was changed. > + =40retval E=46I=5FUNSUPPORTED The platform cannot change the period o= f the timer interrupt. > + =40retval E=46I=5FDEVICE=5FERROR The timer period could not be change= d due to a device error. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +TimerDriverSetTimerPeriod ( > + IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This, > + IN UINT64 TimerPeriod > + ); > + > +/** > + This function retrieves the period of timer interrupts in 100 ns unit= s, > + returns that value in TimerPeriod, and returns E=46I=5FSUCCESS. If Ti= merPeriod > + is NULL, then E=46I=5FINVALID=5FPARAMETER is returned. If a TimerPeri= od of 0 is > + returned, then the timer is currently disabled. > + > + =40param This The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance. > + =40param TimerPeriod A pointer to the timer period to retrieve in 100= ns units. If > + 0 is returned, then the timer is currently disabled. > + > + =40retval E=46I=5FSUCCESS The timer period was returned in TimerPerio= d. > + =40retval E=46I=5FINVALID=5FPARAMETER TimerPeriod is NULL. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +TimerDriverGetTimerPeriod ( > + IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This, > + OUT UINT64 *TimerPeriod > + ); > + > +/** > + This function generates a soft timer interrupt. If the platform does = not support soft > + timer interrupts, then E=46I=5FUNSUPPORTED is returned. Otherwise, E=46= I=5FSUCCESS is returned. > + If a handler has been registered through the E=46I=5FTIMER=5FARCH=5FP= ROTOCOL.RegisterHandler() > + service, then a soft timer interrupt will be generated. If the timer = interrupt is > + enabled when this service is called, then the registered handler will= be invoked. The > + registered handler should not be able to distinguish a hardware-gener= ated timer > + interrupt from a software-generated timer interrupt. > + > + =40param This The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance. > + > + =40retval E=46I=5FSUCCESS The soft timer interrupt was generated. > + =40retval E=46I=5FUNSUPPORTED The platform does not support the gener= ation of soft timer interrupts. > +**/ > +E=46I=5FSTATUS > +E=46IAPI > +TimerDriverGenerateSoftInterrupt ( > + IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This > + ); > + > +/** > + Write Csr TMC=46G register. > + > + =40param A0 The value used to write to the TMC=46G register > + > + =40retval none > +**/ > +extern > +VOID > +LoongarchWriteqTmcfg ( > + IN UINT64 Val > + ); > + > +/** > + Write Csr TINTCLR register. > + > + =40param A0 The value used to write to the TINTCLR register > + > + =40retval none > +**/ > +extern > +VOID > +LoongarchWriteqTintclr ( > + IN UINT64 Val > + ); > + > +=23endif // TIMER=5FH=5F > diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/= TimerConfig.S b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe= /TimerConfig.S > new file mode 100644 > index 0000000000..2f364c193d > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerCo= nfig.S > =40=40 -0,0 +1,38 =40=40 > +=23-------------------------------------------------------------------= ----------- > +=23 > +=23 Timer Cfg for LoongArch > +=23 > +=23 Copyright (c) 2022 Loongson Technology Corporation Limited. All ri= ghts reserved.
> +=23 > +=23 SPDX-License-Identifier: BSD-2-Clause-Patent > +=23 > +=23-------------------------------------------------------------------= ----------- > + > +=23ifndef =5F=5FASSEMBLY=5F=5F > +=23define =5F=5FASSEMBLY=5F=5F > +=23endif > + > +=23include =22Library/Cpu.h=22 > + > +ASM=5FGLOBAL ASM=5FP=46X(LoongarchWriteqTmcfg) > +ASM=5FGLOBAL ASM=5FP=46X(LoongarchWriteqTintclr) > + > +=23 > +=23 Write Csr TMC=46G register. > +=23 =40param A0 The value used to write to the TMC=46G register > +=23 =40retval none > +=23 > + > +ASM=5FP=46X(LoongarchWriteqTmcfg): > + csrwr A0, LOONGARCH=5FCSR=5FTMC=46G > + jirl ZERO, RA,0 > + > +=23 > +=23 Write Csr TINTCLR register. > +=23 =40param A0 The value used to write to the TINTCLR register > +=23 =40retval none > +=23 > + > +ASM=5FP=46X(LoongarchWriteqTintclr): > + csrwr A0, LOONGARCH=5FCSR=5FTINTCLR > + jirl ZERO, RA,0 > diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/= TimerDxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/= TimerDxe.inf > new file mode 100644 > index 0000000000..d4a07c8759 > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDx= e.inf > =40=40 -0,0 +1,44 =40=40 > +=23=23 =40file > +=23 Stable timer driver that provides Timer Arch protocol. > +=23 > +=23 Copyright (c) 2022 Loongson Technology Corporation Limited. All ri= ghts reserved.
> +=23 > +=23 SPDX-License-Identifier: BSD-2-Clause-Patent > +=23 > +=23=23 > +=5BDefines=5D > + IN=46=5FVERSION =3D 0x00010005 > + BASE=5FNAME =3D Timer > + MODULE=5FUNI=5F=46ILE =3D Timer.uni > + =46ILE=5FGUID =3D AEBE2648-47A9-40=46A-83=46D-06AA88443BB2 > + MODULE=5FTYPE =3D DXE=5FDRIVER > + VERSION=5FSTRING =3D 1.0 > + ENTRY=5FPOINT =3D StableTimerDriverInitialize > + > +=23 > +=23 VALID=5FARCHITECTURES =3D LOONGARCH64 > +=23 > + > +=5BSources=5D > + Timer.h > + Timer.c > + TimerConfig.S > + > +=5BPackages=5D > + MdePkg/MdePkg.dec > + Platform/Loongson/LoongArchQemuPkg/Loongson.dec > + > +=5BLibraryClasses=5D > + UefiBootServicesTableLib > + BaseLib > + DebugLib > + UefiDriverEntryPoint > + IoLib > + TimerLib > + > +=5BProtocols=5D > + gEfiCpuArchProtocolGuid =23=23 CONSUMES > + gEfiTimerArchProtocolGuid =23=23 PRODUCES > + > +=5Bdepex=5D > + TRUE > -- > 2.31.1 --636e1a21_4d25e82c_1e57b Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline
Reviewed-by: Chao Li  <lichao=40loongson.cn>


Thanks,
Chao
--------

On 11=E6=9C=88 11 2= 022, at 5:12 =E4=B8=8B=E5=8D=88, xianglai li <lixianglai=40loongson.cn= > wrote:
This driver produces Timer Archite= ctural Protocol,

Registers a timer interrupt and initialize= s the timer.



RE=46: https://bugzilla.tianocore.org/= show=5Fbug.cgi=3Fid=3D4054



Cc: Bibo Mao <maobibo= =40loongson.cn>

Cc: Chao Li <lichao=40loongson.cn>=

Cc: Leif Lindholm <quic=5Fllindhol=40quicinc.com>
Cc: Liming Gao <gaoliming=40byosoft.com.cn>

Cc: Michael D Kinney <michael.d.kinney=40intel.com>

Signed-off-by: xianglai li <lixianglai=40loongson.cn>

---
.../Drivers/StableTimerDxe/Timer.c =7C 388 +++++++++= +++++++++

.../Drivers/StableTimerDxe/Timer.h =7C 172 ++++++= ++

.../Drivers/StableTimerDxe/TimerConfig.S =7C 38 ++
=
.../Drivers/StableTimerDxe/TimerDxe.inf =7C 44 ++

= 4 files changed, 642 insertions(+)

create mode 100644 Platf= orm/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c

create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTim= erDxe/Timer.h
create mode 100644 Platform/Loongson/LoongArc= hQemuPkg/Drivers/StableTimerDxe/TimerConfig.S

create mode 1= 00644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.= inf



diff --git a/Platform/Loongson/LoongArchQemuPkg= /Drivers/StableTimerDxe/Timer.c b/Platform/Loongson/LoongArchQemuPkg/Driv= ers/StableTimerDxe/Timer.c

new file mode 100644

index 0000000000..e09da71272
--- /dev/null

+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c<= /div>
=40=40 -0,0 +1,388 =40=40

+/** =40file
<= br>
+ Timer Architectural Protocol as defined in the DXE CIS
+

+ Copyright (c) 2022 Loongson Technology Corporatio= n Limited. All rights reserved.<BR>

+

+= SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/
+

+=23include <Protocol/Cpu.h><= /div>
+=23include =22Library/Cpu.h=22

+=23include &= lt;Library/DebugLib.h>

+=23include <Library/StableTim= er.h>

+=23include =22Timer.h=22

+=23includ= e <Library/TimerLib.h>

+=23include <Library/UefiBo= otServicesTableLib.h>

+

+//

= +// The handle onto which the Timer Architectural Protocol will be instal= led

+//

+E=46I=5FHANDLE mTimerHandle =3D NULL= ;

+E=46I=5FEVENT EfiExitBootServicesEvent =3D (E=46I=5FEVEN= T)NULL;

+

+//

+// The Timer Arc= hitectural Protocol that this driver produces

+//

=
+E=46I=5FTIMER=5FARCH=5FPROTOCOL mTimer =3D =7B

+ Time= rDriverRegisterHandler,

+ TimerDriverSetTimerPeriod,
<= br>
+ TimerDriverGetTimerPeriod,

+ TimerDriverGenerateS= oftInterrupt

+=7D;

+

+//
<= br>
+// Pointer to the CPU Architectural Protocol instance

<= div>+//

+E=46I=5FCPU=5FARCH=5FPROTOCOL *mCpu;

+
+//

+// The notification function to call = on every timer interrupt.

+// A bug in the compiler prevent= s us from initializing this here.

+//

+E=46I=5F= TIMER=5FNOTI=46Y mTimerNotify=46unction;

+

+/= /

+// The current period of the timer interrupt

+//
+volatile UINT64 mTimerPeriod =3D 0;

+= volatile UINT64 mTimerTicks =3D 0;

+

+//
+// Const frequence in Hz

+//

+exte= rn UINT32 StableTimer=46req;

+

+/**

=
+ Sets the counter value for timer.

+

+ = =40param Count The 16-bit counter value to program into stable timer.
+

+ =40retval VOID

+**/

<= div>+VOID

+SetPitCount (

+ IN UINT64 Count
+ )

+=7B

+ if (Count <=3D 4) =7B=

+ return;

+ =7D

+

+ Count &=3D LOONGARCH=5FCSR=5FTMC=46G=5FTIMEVAL;

+ C= ount =7C=3D LOONGARCH=5FCSR=5FTMC=46G=5FEN =7C LOONGARCH=5FCSR=5FTMC=46G=5F= PERIOD;

+ LoongarchWriteqTmcfg (Count);

+=7D<= /div>
+

+/**

+ Timer Interrupt Handle= r.

+

+ =40param InterruptType The type of int= errupt that occurred

+ =40param SystemContext A pointer to = the system context when the interrupt occurred

+

<= div>+ =40retval VOID

+**/

+VOID

+E=46IAPI

+TimerInterruptHandler (

+ IN E=46= I=5FEXCEPTION=5FTYPE InterruptType,

+ IN E=46I=5FSYSTEM=5FC= ONTEXT SystemContext

+ )

+=7B

+= E=46I=5FTPL OriginalTPL;

+

+ OriginalTPL =3D= gBS->RaiseTPL (TPL=5FHIGH=5FLEVEL);

+

+ /= /

+ // Clear interrupt.

+ //

+ = LoongarchWriteqTintclr (0x1);

+

+ if (mTimerN= otify=46unction =21=3D NULL) =7B

+ //

+ // =40= bug : This does not handle missed timer interrupts

+ //
+ mTimerNotify=46unction (mTimerPeriod);

+ =7D
+

+ gBS->RestoreTPL (OriginalTPL);
+=7D

+

+/**

+ This functi= on registers the handler Notify=46unction so it is called every time
+ the timer interrupt fires. It also passes the amount of time = since the last

+ handler call to the Notify=46unction. If N= otify=46unction is NULL, then the

+ handler is unregistered= . If the handler is registered, then E=46I=5FSUCCESS is

+ r= eturned. If the CPU does not support registering a timer interrupt handle= r,

+ then E=46I=5FUNSUPPORTED is returned. If an attempt is= made to register a handler

+ when a handler is already reg= istered, then E=46I=5FALREADY=5FSTARTED is returned.

+ If a= n attempt is made to unregister a handler when a handler is not registere= d,

+ then E=46I=5FINVALID=5FPARAMETER is returned. If an er= ror occurs attempting to

+ register the Notify=46unction wi= th the timer interrupt, then E=46I=5FDEVICE=5FERROR

+ is re= turned.

+

+ =40param This The E=46I=5FTIMER=5F= ARCH=5FPROTOCOL instance.

+ =40param Notify=46unction The f= unction to call when a timer interrupt fires. This

+ functi= on executes at TPL=5FHIGH=5FLEVEL. The DXE Core will

+ regi= ster a handler for the timer interrupt, so it can know

+ ho= w much time has passed. This information is used to

+ signa= l timer based events. NULL will unregister the handler.

+
+ =40retval E=46I=5FSUCCESS The timer handler was registered= .

+ =40retval E=46I=5FUNSUPPORTED The platform does not sup= port timer interrupts.

+ =40retval E=46I=5FALREADY=5FSTARTE= D Notify=46unction is not NULL, and a handler is already

+ = registered.

+ =40retval E=46I=5FINVALID=5FPARAMETER Notify=46= unction is NULL, and a handler was not

+ previously registe= red.

+ =40retval E=46I=5FDEVICE=5FERROR The timer handler c= ould not be registered.

+**/

+E=46I=5FSTATUS<= /div>
+E=46IAPI

+TimerDriverRegisterHandler (
=
+ IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This,

+ IN E= =46I=5FTIMER=5FNOTI=46Y Notify=46unction

+ )

= +=7B

+ //

+ // Check for invalid parameters
+ //

+ if ((Notify=46unction =3D=3D NULL)
+ && (mTimerNotify=46unction =3D=3D NULL))

+ =7B

+ return E=46I=5FINVALID=5FPARAMETER;

+ =7D

+

+ if ((Notify=46unction =21=3D NULL)=

+ && mTimerNotify=46unction =21=3D NULL)

=
+ =7B

+ return E=46I=5FALREADY=5FSTARTED;

+ =7D

+

+ mTimerNotify=46unction =3D Notify= =46unction;

+

+ return E=46I=5FSUCCESS;
=
+=7D

+

+/**

+ This fun= ction adjusts the period of timer interrupts to the value specified
=
+ by TimerPeriod. If the timer period is updated, then the selec= ted timer

+ period is stored in E=46I=5FTIMER.TimerPeriod, = and E=46I=5FSUCCESS is returned. If

+ the timer hardware is= not programmable, then E=46I=5FUNSUPPORTED is returned.

+ = If an error occurs while attempting to update the timer period, then the<= /div>
+ timer hardware will be put back in its state prior to thi= s call, and

+ E=46I=5FDEVICE=5FERROR is returned. If TimerP= eriod is 0, then the timer interrupt

+ is disabled. This is= not the same as disabling the CPU's interrupts.

+ Instead,= it must either turn off the timer hardware, or it must adjust the
<= br>
+ interrupt controller so that a CPU interrupt is not generated w= hen the timer

+ interrupt fires.

+

<= div>+ =40param This The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance.
+ =40param TimerPeriod The rate to program the timer interrupt in = 100 nS units. If

+ the timer hardware is not programmable, = then E=46I=5FUNSUPPORTED is

+ returned. If the timer is pro= grammable, then the timer period

+ will be rounded up to th= e nearest timer period that is supported

+ by the timer har= dware. If TimerPeriod is set to 0, then the

+ timer interru= pts will be disabled.

+

+ =40retval E=46I=5FS= UCCESS The timer period was changed.

+ =40retval E=46I=5FUN= SUPPORTED The platform cannot change the period of the timer interrupt.
+ =40retval E=46I=5FDEVICE=5FERROR The timer period could no= t be changed due to a device error.

+**/

+E=46= I=5FSTATUS

+E=46IAPI

+TimerDriverSetTimerPeri= od (

+ IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This,

<= div>+ IN UINT64 TimerPeriod

+ )

+=7B
+ UINT64 TimerCount;

+

+ if (TimerPerio= d =3D=3D 0) =7B

+ //

+ // Disable timer inter= rupt for a TimerPeriod of 0

+ //

+ mCpu->D= isableInterrupt (mCpu);

+ =7D else =7B

+
+ TimerCount =3D TimerPeriod * StableTimer=46req / 10000000ULL;=

+

+ if (TimerCount >=3D BIT48) =7B
<= br>
+ TimerCount =3D 0;

+ =7D

+

=
+ //

+ // Program the stable timer with the new count = value

+ //

+ mTimerTicks =3D TimerCount;
+ SetPitCount (TimerCount);

+

+ //<= /div>
+ // Enable timer interrupt

+ //

+ mCpu->EnableInterrupt (mCpu);

+ =7D

+<= /div>
+ //

+ // Save the new timer period

=
+ //

+ mTimerPeriod =3D TimerPeriod;

+
+ return E=46I=5FSUCCESS;

+=7D

+=

+/**

+ This function retrieves the period of= timer interrupts in 100 ns units,

+ returns that value in = TimerPeriod, and returns E=46I=5FSUCCESS. If TimerPeriod

+ = is NULL, then E=46I=5FINVALID=5FPARAMETER is returned. If a TimerPeriod o= f 0 is

+ returned, then the timer is currently disabled.
+

+ =40param This The E=46I=5FTIMER=5FARCH=5FPR= OTOCOL instance.

+ =40param TimerPeriod A pointer to the ti= mer period to retrieve in 100 ns units. If

+ 0 is returned,= then the timer is currently disabled.

+

+ =40= retval E=46I=5FSUCCESS The timer period was returned in TimerPeriod.
+ =40retval E=46I=5FINVALID=5FPARAMETER TimerPeriod is NULL.
+**/

+E=46I=5FSTATUS

+E=46IAPI
+TimerDriverGetTimerPeriod (

+ IN E=46I=5FTIMER= =5FARCH=5FPROTOCOL *This,

+ OUT UINT64 *TimerPeriod
+ )

+=7B

+ if (TimerPeriod =3D=3D NULL= ) =7B

+ return E=46I=5FINVALID=5FPARAMETER;

+= =7D

+

+ *TimerPeriod =3D mTimerPeriod;
=
+

+ return E=46I=5FSUCCESS;

+=7D
+

+/**

+ Disable the timer
+ DXE Core will disable the timer after all the event handlers hav= e run.

+

+ =40param=5Bin=5D Event The Event t= hat is being processed

+ =40param=5Bin=5D Context Event Con= text

+**/

+VOID

+E=46IAPI
=
+ExitBootServicesEvent (

+ IN E=46I=5FEVENT Event,=

+ IN VOID *Context

+ )

+=7B
+ /*

+ * Disable timer interrupt when exiting b= oot service

+ */

+ LoongarchWriteqTmcfg (0);<= /div>
+=7D

+

+/**

+ Thi= s function generates a soft timer interrupt. If the platform does not sup= port soft

+ timer interrupts, then E=46I=5FUNSUPPORTED is r= eturned. Otherwise, E=46I=5FSUCCESS is returned.

+ If a han= dler has been registered through the E=46I=5FTIMER=5FARCH=5FPROTOCOL.Regi= sterHandler ()

+ service, then a soft timer interrupt will = be generated. If the timer interrupt is

+ enabled when this= service is called, then the registered handler will be invoked. The
+ registered handler should not be able to distinguish a hardwa= re-generated timer

+ interrupt from a software-generated ti= mer interrupt.

+

+ =40param This The E=46I=5F= TIMER=5FARCH=5FPROTOCOL instance.

+

+ =40retv= al E=46I=5FSUCCESS The soft timer interrupt was generated.

= + =40retval E=46I=5FUNSUPPORTED The platform does not support the generat= ion of soft timer interrupts.

+**/

+E=46I=5FS= TATUS

+E=46IAPI

+TimerDriverGenerateSoftInter= rupt (

+ IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This

=
+ )

+=7B

+ return E=46I=5FUNSUPPORTED;
+=7D

+

+/**

+ Init= ialize the Timer Architectural Protocol driver

+

<= div>+ =40param ImageHandle ImageHandle of the loaded driver

+ =40param SystemTable Pointer to the System Table

+
=
+ =40retval E=46I=5FSUCCESS Timer Architectural Protocol created=

+ =40retval E=46I=5FOUT=5FO=46=5FRESOURCES Not enough reso= urces available to initialize driver.

+ =40retval E=46I=5FD= EVICE=5FERROR A device error occurred attempting to initialize the driver= .

+**/

+E=46I=5FSTATUS

+E=46IAP= I

+StableTimerDriverInitialize (

+ IN E=46I=5F= HANDLE ImageHandle,

+ IN E=46I=5FSYSTEM=5FTABLE *SystemTabl= e

+ )

+=7B

+ E=46I=5FSTATUS Sta= tus;

+ UINT32 TimerVector;

+

+ = //

+ // Initialize the pointer to our notify function.
+ //

+ mTimerNotify=46unction =3D NULL;

=
+

+ //

+ // Make sure the Timer Architec= tural Protocol is not already installed in the system

+ //<= /div>
+ ASSERT=5FPROTOCOL=5FALREADY=5FINSTALLED (NULL, &gEfiT= imerArchProtocolGuid);

+

+ //

+= // =46ind the CPU architectural protocol.

+ //

+ Status =3D gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NUL= L, (VOID **) &mCpu);

+ ASSERT=5FE=46I=5FERROR (Status);=

+

+ //

+ // =46orce the timer = to be disabled

+ //

+ Status =3D TimerDriverS= etTimerPeriod (&mTimer, 0);

+ ASSERT=5FE=46I=5FERROR (S= tatus);

+

+ //

+ // Calculate c= onst frequence

+ //

+ StableTimer=46req =3D C= alcConst=46req ();

+ DEBUG ((DEBUG=5FIN=46O, =22=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3DStable timer freq %d Hz=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=5Cn=22, StableTimer=46req));

+

+ //=

+ // Install interrupt handler for Stable Timer =230 (ISA = IRQ0)

+ //

+ TimerVector =3D EXCEPT=5FLOONGAR= CH=5FINT=5FTIMER;

+ Status =3D mCpu->RegisterInterruptHa= ndler (mCpu, TimerVector, TimerInterruptHandler);

+ ASSERT=5F= E=46I=5FERROR (Status);

+

+ //

= + // Enable TI local timer interrupt

+ //

+ C= puSetIP (1 << 11);

+

+ //

+ // =46orce the timer to be enabled at its default period

+ //

+ Status =3D TimerDriverSetTimerPeriod (&mTimer, = DE=46AULT=5FTIMER=5FTICK=5FDURATION);

+ ASSERT=5FE=46I=5FER= ROR (Status);

+

+ //

+ // Insta= ll the Timer Architectural Protocol onto a new handle

+ //<= /div>
+ Status =3D gBS->InstallMultipleProtocolInterfaces (
+ &mTimerHandle,

+ &gEfiTimerArchProtoc= olGuid, &mTimer,

+ NULL

+ );

+

+ ASSERT=5FE=46I=5FERROR (Status);

+
+ // Register for an ExitBootServicesEvent

+ Stat= us =3D gBS->CreateEvent (EVT=5FSIGNAL=5FEXIT=5FBOOT=5FSERVICES, TPL=5F= NOTI=46Y, ExitBootServicesEvent, NULL,

+ &EfiExitBootSe= rvicesEvent);

+ ASSERT=5FE=46I=5FERROR (Status);

<= div>+

+ return Status;

+=7D

dif= f --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer= .h b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h
new file mode 100644

index 0000000000..84036cab= 00

--- /dev/null

+++ b/Platform/Loongson/Loon= gArchQemuPkg/Drivers/StableTimerDxe/Timer.h

=40=40 -0,0 +1,= 172 =40=40

+/** =40file

+ Private data struct= ures

+

+ Copyright (c) 2022 Loongson Technolo= gy Corporation Limited. All rights reserved.<BR>

+
+ SPDX-License-Identifier: BSD-2-Clause-Patent

= +

+**/

+

+=23ifndef TIMER=5FH=5F=

+=23define TIMER=5FH=5F

+

+=23= include <Protocol/Timer.h>

+

+=23define= DE=46AULT=5FTIMER=5FTICK=5FDURATION 100000 //10ms =3D 100000 100 ns unit= s

+=23define SR=5FIP7 (1 << 15)

+//
+// =46unction Prototypes

+//

+ext= ern UINT32 E=46IAPI CpuGetCompare(VOID);

+extern VOID E=46I= API CpuSetCompare(IN UINT32 val);

+extern VOID E=46IAPI Cpu= SetIP(IN UINT32 val);

+extern VOID E=46IAPI ClearC0Cause(IN= UINT32 val);

+extern VOID E=46IAPI ClearC0Status(IN UINT32= val);

+/**

+ Initialize the Timer Architectu= ral Protocol driver

+

+ =40param ImageHandle = ImageHandle of the loaded driver

+ =40param SystemTable Poi= nter to the System Table

+

+ =40retval E=46I=5F= SUCCESS Timer Architectural Protocol created

+ =40retval E=46= I=5FOUT=5FO=46=5FRESOURCES Not enough resources available to initialize d= river.

+ =40retval E=46I=5FDEVICE=5FERROR A device error oc= curred attempting to initialize the driver.

+**/

<= div>+E=46I=5FSTATUS

+E=46IAPI

+TimerDriverIni= tialize (

+ IN E=46I=5FHANDLE ImageHandle,

+ = IN E=46I=5FSYSTEM=5FTABLE *SystemTable

+ );

+=

+/**

+ This function adjusts the period of t= imer interrupts to the value specified

+ by TimerPeriod. If= the timer period is updated, then the selected timer

+ per= iod is stored in E=46I=5FTIMER.TimerPeriod, and E=46I=5FSUCCESS is return= ed. If

+ the timer hardware is not programmable, then E=46I= =5FUNSUPPORTED is returned.

+ If an error occurs while atte= mpting to update the timer period, then the

+ timer hardwar= e will be put back in its state prior to this call, and

+ E= =46I=5FDEVICE=5FERROR is returned. If TimerPeriod is 0, then the timer in= terrupt

+ is disabled. This is not the same as disabling th= e CPU's interrupts.

+ Instead, it must either turn off the = timer hardware, or it must adjust the

+ interrupt controlle= r so that a CPU interrupt is not generated when the timer

+= interrupt fires.

+

+ =40param This The E=46I= =5FTIMER=5FARCH=5FPROTOCOL instance.

+ =40param Notify=46un= ction The rate to program the timer interrupt in 100 nS units. If
+ the timer hardware is not programmable, then E=46I=5FUNSUPPORTED= is

+ returned. If the timer is programmable, then the time= r period

+ will be rounded up to the nearest timer period t= hat is supported

+ by the timer hardware. If TimerPeriod is= set to 0, then the

+ timer interrupts will be disabled.
+

+ =40retval E=46I=5FSUCCESS The timer period = was changed.

+ =40retval E=46I=5FUNSUPPORTED The platform c= annot change the period of the timer interrupt.

+ =40retval= E=46I=5FDEVICE=5FERROR The timer period could not be changed due to a de= vice error.

+**/

+E=46I=5FSTATUS

+E=46IAPI

+TimerDriverRegisterHandler (

+ I= N E=46I=5FTIMER=5FARCH=5FPROTOCOL *This,

+ IN E=46I=5FTIMER= =5FNOTI=46Y Notify=46unction

+ );

+

=
+/**

+ This function adjusts the period of timer inter= rupts to the value specified

+ by TimerPeriod. If the timer= period is updated, then the selected timer

+ period is sto= red in E=46I=5FTIMER.TimerPeriod, and E=46I=5FSUCCESS is returned. If
+ the timer hardware is not programmable, then E=46I=5FUNSUPPO= RTED is returned.

+ If an error occurs while attempting to = update the timer period, then the

+ timer hardware will be = put back in its state prior to this call, and

+ E=46I=5FDEV= ICE=5FERROR is returned. If TimerPeriod is 0, then the timer interrupt
+ is disabled. This is not the same as disabling the CPU's in= terrupts.

+ Instead, it must either turn off the timer hard= ware, or it must adjust the

+ interrupt controller so that = a CPU interrupt is not generated when the timer

+ interrupt= fires.

+

+ =40param This The E=46I=5FTIMER=5F= ARCH=5FPROTOCOL instance.

+ =40param TimerPeriod The rate t= o program the timer interrupt in 100 nS units. If

+ the tim= er hardware is not programmable, then E=46I=5FUNSUPPORTED is

+ returned. If the timer is programmable, then the timer period
+ will be rounded up to the nearest timer period that is supported=

+ by the timer hardware. If TimerPeriod is set to 0, then = the

+ timer interrupts will be disabled.

+
+ =40retval E=46I=5FSUCCESS The timer period was changed.
+ =40retval E=46I=5FUNSUPPORTED The platform cannot change the= period of the timer interrupt.

+ =40retval E=46I=5FDEVICE=5F= ERROR The timer period could not be changed due to a device error.
<= br>
+**/

+E=46I=5FSTATUS

+E=46IAPI
<= br>
+TimerDriverSetTimerPeriod (

+ IN E=46I=5FTIMER=5FA= RCH=5FPROTOCOL *This,

+ IN UINT64 TimerPeriod

+ );

+

+/**

+ This function re= trieves the period of timer interrupts in 100 ns units,

+ r= eturns that value in TimerPeriod, and returns E=46I=5FSUCCESS. If TimerPe= riod

+ is NULL, then E=46I=5FINVALID=5FPARAMETER is returne= d. If a TimerPeriod of 0 is

+ returned, then the timer is c= urrently disabled.

+

+ =40param This The E=46= I=5FTIMER=5FARCH=5FPROTOCOL instance.

+ =40param TimerPerio= d A pointer to the timer period to retrieve in 100 ns units. If

=
+ 0 is returned, then the timer is currently disabled.

+

+ =40retval E=46I=5FSUCCESS The timer period was returne= d in TimerPeriod.

+ =40retval E=46I=5FINVALID=5FPARAMETER T= imerPeriod is NULL.

+**/

+E=46I=5FSTATUS
+E=46IAPI

+TimerDriverGetTimerPeriod (

<= div>+ IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *This,

+ OUT UINT6= 4 *TimerPeriod

+ );

+

+/**
+ This function generates a soft timer interrupt. If the platfo= rm does not support soft

+ timer interrupts, then E=46I=5FU= NSUPPORTED is returned. Otherwise, E=46I=5FSUCCESS is returned.

=
+ If a handler has been registered through the E=46I=5FTIMER=5FARCH=5F= PROTOCOL.RegisterHandler()

+ service, then a soft timer int= errupt will be generated. If the timer interrupt is

+ enabl= ed when this service is called, then the registered handler will be invok= ed. The

+ registered handler should not be able to distingu= ish a hardware-generated timer

+ interrupt from a software-= generated timer interrupt.

+

+ =40param This = The E=46I=5FTIMER=5FARCH=5FPROTOCOL instance.

+

+ =40retval E=46I=5FSUCCESS The soft timer interrupt was generated.
+ =40retval E=46I=5FUNSUPPORTED The platform does not support= the generation of soft timer interrupts.

+**/

+E=46I=5FSTATUS

+E=46IAPI

+TimerDriverGener= ateSoftInterrupt (

+ IN E=46I=5FTIMER=5FARCH=5FPROTOCOL *Th= is

+ );

+

+/**

+ = Write Csr TMC=46G register.

+

+ =40param A0 T= he value used to write to the TMC=46G register

+

<= div>+ =40retval none

+**/

+extern

+VOID

+LoongarchWriteqTmcfg (

+ IN UINT64 = Val

+ );

+

+/**

+= Write Csr TINTCLR register.

+

+ =40param A0 = The value used to write to the TINTCLR register

+

=
+ =40retval none

+**/

+extern

<= div>+VOID

+LoongarchWriteqTintclr (

+ IN UINT= 64 Val

+ );

+

+=23endif // TIME= R=5FH=5F

diff --git a/Platform/Loongson/LoongArchQemuPkg/Dr= ivers/StableTimerDxe/TimerConfig.S b/Platform/Loongson/LoongArchQemuPkg/D= rivers/StableTimerDxe/TimerConfig.S

new file mode 100644
index 0000000000..2f364c193d

--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe= /TimerConfig.S

=40=40 -0,0 +1,38 =40=40

+=23-= -------------------------------------------------------------------------= ----

+=23

+=23 Timer Cfg for LoongArch
<= br>
+=23

+=23 Copyright (c) 2022 Loongson Technology Co= rporation Limited. All rights reserved.<BR>

+=23
+=23 SPDX-License-Identifier: BSD-2-Clause-Patent

+=23

+=23-------------------------------------------------= -----------------------------

+

+=23ifndef =5F= =5FASSEMBLY=5F=5F

+=23define =5F=5FASSEMBLY=5F=5F

=
+=23endif

+

+=23include =22Library/Cpu.h= =22

+

+ASM=5FGLOBAL ASM=5FP=46X(LoongarchWrit= eqTmcfg)

+ASM=5FGLOBAL ASM=5FP=46X(LoongarchWriteqTintclr)<= /div>
+

+=23

+=23 Write Csr TMC=46G r= egister.

+=23 =40param A0 The value used to write to the TM= C=46G register

+=23 =40retval none

+=23
=
+

+ASM=5FP=46X(LoongarchWriteqTmcfg):

+ csrwr A0, LOONGARCH=5FCSR=5FTMC=46G

+ jirl ZERO, RA,0
+

+=23

+=23 Write Csr TINTCLR re= gister.

+=23 =40param A0 The value used to write to the TIN= TCLR register

+=23 =40retval none

+=23
<= br>
+

+ASM=5FP=46X(LoongarchWriteqTintclr):

+ csrwr A0, LOONGARCH=5FCSR=5FTINTCLR

+ jirl ZERO, RA,0<= /div>
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/Sta= bleTimerDxe/TimerDxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/Sta= bleTimerDxe/TimerDxe.inf

new file mode 100644

index 0000000000..d4a07c8759

--- /dev/null

+= ++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.i= nf

=40=40 -0,0 +1,44 =40=40

+=23=23 =40file
+=23 Stable timer driver that provides Timer Arch protocol.<= /div>
+=23

+=23 Copyright (c) 2022 Loongson Technol= ogy Corporation Limited. All rights reserved.<BR>

+=23=

+=23 SPDX-License-Identifier: BSD-2-Clause-Patent
+=23

+=23=23

+=5BDefines=5D

+ IN=46=5FVERSION =3D 0x00010005

+ BASE=5FNAME =3D Timer=

+ MODULE=5FUNI=5F=46ILE =3D Timer.uni

+ =46I= LE=5FGUID =3D AEBE2648-47A9-40=46A-83=46D-06AA88443BB2

+ MO= DULE=5FTYPE =3D DXE=5FDRIVER

+ VERSION=5FSTRING =3D 1.0
+ ENTRY=5FPOINT =3D StableTimerDriverInitialize

= +

+=23

+=23 VALID=5FARCHITECTURES =3D LOONGAR= CH64

+=23

+

+=5BSources=5D
+ Timer.h

+ Timer.c

+ TimerConfig.S=

+

+=5BPackages=5D

+ MdePkg/Mde= Pkg.dec

+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+

+=5BLibraryClasses=5D

+ UefiBo= otServicesTableLib

+ BaseLib

+ DebugLib
=
+ UefiDriverEntryPoint

+ IoLib

+ Tim= erLib

+

+=5BProtocols=5D

+ gEfi= CpuArchProtocolGuid =23=23 CONSUMES

+ gEfiTimerArchProtocol= Guid =23=23 PRODUCES

+

+=5Bdepex=5D

=
+ TRUE

--

2.31.1
--636e1a21_4d25e82c_1e57b--