sifive_prci: Read and write PRCI registers

Writes to the SiFive PRCI registers are preserved while leaving the
ready bits set for the HFX/HFR oscillators and the lock bit set for the
PLL.

Signed-off-by: Nathaniel Graff <nathaniel.graff@sifive.com>
Reviewed-by: Michael Clark <mjc@sifive.com>
Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
This commit is contained in:
Nathaniel Graff 2018-07-24 09:52:46 -07:00 committed by Palmer Dabbelt
parent b55d7d34f6
commit b9d1848ebe
No known key found for this signature in database
GPG key ID: EF4CA1502CCBAB41
2 changed files with 73 additions and 8 deletions

View file

@ -24,15 +24,18 @@
#include "target/riscv/cpu.h"
#include "hw/riscv/sifive_prci.h"
/* currently implements enough to mock freedom-e-sdk BSP clock programming */
static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size)
{
if (addr == 0 /* PRCI_HFROSCCFG */) {
return 1 << 31; /* ROSC_RDY */
}
if (addr == 8 /* PRCI_PLLCFG */) {
return 1 << 31; /* PLL_LOCK */
SiFivePRCIState *s = opaque;
switch (addr) {
case SIFIVE_PRCI_HFROSCCFG:
return s->hfrosccfg;
case SIFIVE_PRCI_HFXOSCCFG:
return s->hfxosccfg;
case SIFIVE_PRCI_PLLCFG:
return s->pllcfg;
case SIFIVE_PRCI_PLLOUTDIV:
return s->plloutdiv;
}
hw_error("%s: read: addr=0x%x\n", __func__, (int)addr);
return 0;
@ -41,7 +44,30 @@ static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size)
static void sifive_prci_write(void *opaque, hwaddr addr,
uint64_t val64, unsigned int size)
{
/* discard writes */
SiFivePRCIState *s = opaque;
switch (addr) {
case SIFIVE_PRCI_HFROSCCFG:
s->hfrosccfg = (uint32_t) val64;
/* OSC stays ready */
s->hfrosccfg |= SIFIVE_PRCI_HFROSCCFG_RDY;
break;
case SIFIVE_PRCI_HFXOSCCFG:
s->hfxosccfg = (uint32_t) val64;
/* OSC stays ready */
s->hfxosccfg |= SIFIVE_PRCI_HFXOSCCFG_RDY;
break;
case SIFIVE_PRCI_PLLCFG:
s->pllcfg = (uint32_t) val64;
/* PLL stays locked */
s->pllcfg |= SIFIVE_PRCI_PLLCFG_LOCK;
break;
case SIFIVE_PRCI_PLLOUTDIV:
s->plloutdiv = (uint32_t) val64;
break;
default:
hw_error("%s: bad write: addr=0x%x v=0x%x\n",
__func__, (int)addr, (int)val64);
}
}
static const MemoryRegionOps sifive_prci_ops = {
@ -61,6 +87,13 @@ static void sifive_prci_init(Object *obj)
memory_region_init_io(&s->mmio, obj, &sifive_prci_ops, s,
TYPE_SIFIVE_PRCI, 0x8000);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
s->hfrosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
s->hfxosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
s->pllcfg = (SIFIVE_PRCI_PLLCFG_REFSEL | SIFIVE_PRCI_PLLCFG_BYPASS |
SIFIVE_PRCI_PLLCFG_LOCK);
s->plloutdiv = SIFIVE_PRCI_PLLOUTDIV_DIV1;
}
static const TypeInfo sifive_prci_info = {

View file

@ -19,6 +19,34 @@
#ifndef HW_SIFIVE_PRCI_H
#define HW_SIFIVE_PRCI_H
enum {
SIFIVE_PRCI_HFROSCCFG = 0x0,
SIFIVE_PRCI_HFXOSCCFG = 0x4,
SIFIVE_PRCI_PLLCFG = 0x8,
SIFIVE_PRCI_PLLOUTDIV = 0xC
};
enum {
SIFIVE_PRCI_HFROSCCFG_RDY = (1 << 31),
SIFIVE_PRCI_HFROSCCFG_EN = (1 << 30)
};
enum {
SIFIVE_PRCI_HFXOSCCFG_RDY = (1 << 31),
SIFIVE_PRCI_HFXOSCCFG_EN = (1 << 30)
};
enum {
SIFIVE_PRCI_PLLCFG_PLLSEL = (1 << 16),
SIFIVE_PRCI_PLLCFG_REFSEL = (1 << 17),
SIFIVE_PRCI_PLLCFG_BYPASS = (1 << 18),
SIFIVE_PRCI_PLLCFG_LOCK = (1 << 31)
};
enum {
SIFIVE_PRCI_PLLOUTDIV_DIV1 = (1 << 8)
};
#define TYPE_SIFIVE_PRCI "riscv.sifive.prci"
#define SIFIVE_PRCI(obj) \
@ -30,6 +58,10 @@ typedef struct SiFivePRCIState {
/*< public >*/
MemoryRegion mmio;
uint32_t hfrosccfg;
uint32_t hfxosccfg;
uint32_t pllcfg;
uint32_t plloutdiv;
} SiFivePRCIState;
DeviceState *sifive_prci_create(hwaddr addr);