gint/src/cpg/cpg.c

160 lines
3.6 KiB
C
Raw Normal View History

//---
// gint:clock:freq - Clock frequency management
//---
#include <gint/drivers.h>
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
#include <gint/drivers/states.h>
#include <gint/clock.h>
#include <gint/hardware.h>
#include <gint/mpu/cpg.h>
//---
// Driver storage
//---
/* Local copy of the CPG settings */
GBSS static clock_frequency_t freq;
/* clock_freq() - get the frequency of the main clocks */
const clock_frequency_t *clock_freq(void)
{
return &freq;
}
//---
// SH7705 Clock signals
//---
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
#define CPG SH7705_CPG
static void sh7705_probe(void)
{
/* According to Sentaro21 in the sources of Ftune 1.0.1, the clock mode
is thought to be 5, which means that:
- CPG input is XTAL (14.745'600 MHz)
- PLL2 is active and *2 (29.491'200 MHz)
- CKIO is output from PLL2 (29.491'200 MHz) */
int xtal = 14745600;
int pll2 = 2;
int ckio = xtal * pll2;
/* This signal is multiplied by the PLL1 circuit */
int pll1 = CPG.FRQCR.STC + 1;
/* Iphi and Pphi have dividers (Bphi is always equal to CKIO) */
int idiv = CPG.FRQCR.IFC;
int pdiv = CPG.FRQCR.PFC;
/* Fill in the setting structure */
freq.PLL1 = pll1;
freq.PLL2 = pll2;
freq.Bphi_div = 1;
freq.Iphi_div = idiv + 1;
freq.Pphi_div = pdiv + 1;
/* Deduce the frequency of the main clocks. This value is ckio/3 */
int ckio_3 = 9830400;
/* Exchange the setting values 2 and 3 (corresponding to /3 and /4)
This means that /1, /2, /4 are now 0, 1, 2, which is perfect for a
quick bit shift */
idiv = idiv ^ (idiv >> 1);
pdiv = pdiv ^ (pdiv >> 1);
freq.CKIO_f = ckio;
freq.Bphi_f = ckio;
freq.Iphi_f = (idiv == 3) ? ckio_3 : ckio >> idiv;
freq.Pphi_f = (pdiv == 3) ? ckio_3 : ckio >> pdiv;
}
#undef CPG
#endif /* FX9860G and platform-agnostic */
//---
// SH7305 clock signals
//---
#define CPG SH7305_CPG
static void sh7305_probe(void)
{
/* The meaning of the PLL setting on SH7305 differs from the
documentation of SH7224; the value must not be doubled. */
2022-04-12 17:23:18 +02:00
int pll = CPG.FRQCR.STC + 1;
freq.PLL = pll;
/* The FLL ratio is the value of the setting, halved if SELXM=1 */
int fll = CPG.FLLFRQ.FLF;
if(CPG.FLLFRQ.SELXM == 1) fll >>= 1;
freq.FLL = fll;
/* On SH7724, the divider ratio is given by 1 / (setting + 1), but on
the SH7305 it is 1 / (2^setting + 1). */
2022-04-12 17:23:18 +02:00
int divb = CPG.FRQCR.BFC;
int divi = CPG.FRQCR.IFC;
int divp = CPG.FRQCR.P1FC;
freq.Bphi_div = 1 << (divb + 1);
freq.Iphi_div = 1 << (divi + 1);
freq.Pphi_div = 1 << (divp + 1);
/* Deduce the input frequency of divider 1 */
int base = 32768;
if(CPG.PLLCR.FLLE) base *= fll;
if(CPG.PLLCR.PLLE) base *= pll;
/* And the frequency of all other input clocks */
freq.RTCCLK_f = 32768;
freq.Bphi_f = base >> (divb + 1);
freq.Iphi_f = base >> (divi + 1);
freq.Pphi_f = base >> (divp + 1);
}
#undef CPG
//---
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
// Initialization
//---
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
static void configure(void)
{
/* Disable spread spectrum in SSGSCR */
if(isSH4())
{
SH7305_CPG.SSCGCR.SSEN = 0;
}
/* This avoids warnings about sh7705_probe() being undefined when
building for fxcg50 */
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
isSH3() ? sh7705_probe() :
#endif
sh7305_probe();
}
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
//---
// State and driver metadata
//---
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
static void hsave(cpg_state_t *s)
{
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
if(isSH4()) s->SSCGCR = SH7305_CPG.SSCGCR.lword;
}
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
static void hrestore(cpg_state_t const *s)
{
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
if(isSH4()) SH7305_CPG.SSCGCR.lword = s->SSCGCR;
}
gint_driver_t drv_cpg = {
.name = "CPG",
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
.configure = configure,
.hsave = (void *)hsave,
.hrestore = (void *)hrestore,
.state_size = sizeof(cpg_state_t),
};
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
GINT_DECLARE_DRIVER(05, drv_cpg);