qemu
1/*
2* Status and system control registers for ARM RealView/Versatile boards.
3*
4* Copyright (c) 2006-2007 CodeSourcery.
5* Written by Paul Brook
6*
7* This code is licensed under the GPL.
8*/
9
10#include "qemu/osdep.h"11#include "hw/irq.h"12#include "hw/qdev-properties.h"13#include "qemu/timer.h"14#include "sysemu/runstate.h"15#include "qemu/bitops.h"16#include "hw/sysbus.h"17#include "migration/vmstate.h"18#include "hw/arm/primecell.h"19#include "qemu/log.h"20#include "qemu/module.h"21#include "qom/object.h"22
23#define LOCK_VALUE 0xa05f24
25#define TYPE_ARM_SYSCTL "realview_sysctl"26OBJECT_DECLARE_SIMPLE_TYPE(arm_sysctl_state, ARM_SYSCTL)27
28struct arm_sysctl_state {29SysBusDevice parent_obj;30
31MemoryRegion iomem;32qemu_irq pl110_mux_ctrl;33
34uint32_t sys_id;35uint32_t leds;36uint16_t lockval;37uint32_t cfgdata1;38uint32_t cfgdata2;39uint32_t flags;40uint32_t nvflags;41uint32_t resetlevel;42uint32_t proc_id;43uint32_t sys_mci;44uint32_t sys_cfgdata;45uint32_t sys_cfgctrl;46uint32_t sys_cfgstat;47uint32_t sys_clcd;48uint32_t mb_clock[6];49uint32_t *db_clock;50uint32_t db_num_vsensors;51uint32_t *db_voltage;52uint32_t db_num_clocks;53uint32_t *db_clock_reset;54};55
56static const VMStateDescription vmstate_arm_sysctl = {57.name = "realview_sysctl",58.version_id = 4,59.minimum_version_id = 1,60.fields = (const VMStateField[]) {61VMSTATE_UINT32(leds, arm_sysctl_state),62VMSTATE_UINT16(lockval, arm_sysctl_state),63VMSTATE_UINT32(cfgdata1, arm_sysctl_state),64VMSTATE_UINT32(cfgdata2, arm_sysctl_state),65VMSTATE_UINT32(flags, arm_sysctl_state),66VMSTATE_UINT32(nvflags, arm_sysctl_state),67VMSTATE_UINT32(resetlevel, arm_sysctl_state),68VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),69VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),70VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),71VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),72VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3),73VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4),74VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks,754, vmstate_info_uint32, uint32_t),76VMSTATE_END_OF_LIST()77}78};79
80/* The PB926 actually uses a different format for
81* its SYS_ID register. Fortunately the bits which are
82* board type on later boards are distinct.
83*/
84#define BOARD_ID_PB926 0x10085#define BOARD_ID_EB 0x14086#define BOARD_ID_PBA8 0x17887#define BOARD_ID_PBX 0x18288#define BOARD_ID_VEXPRESS 0x19089
90static int board_id(arm_sysctl_state *s)91{
92/* Extract the board ID field from the SYS_ID register value */93return (s->sys_id >> 16) & 0xfff;94}
95
96static void arm_sysctl_reset(DeviceState *d)97{
98arm_sysctl_state *s = ARM_SYSCTL(d);99int i;100
101s->leds = 0;102s->lockval = 0;103s->cfgdata1 = 0;104s->cfgdata2 = 0;105s->flags = 0;106s->resetlevel = 0;107/* Motherboard oscillators (in Hz) */108s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */109s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */110s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */111s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */112s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */113s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */114/* Daughterboard oscillators: reset from property values */115for (i = 0; i < s->db_num_clocks; i++) {116s->db_clock[i] = s->db_clock_reset[i];117}118if (board_id(s) == BOARD_ID_VEXPRESS) {119/* On VExpress this register will RAZ/WI */120s->sys_clcd = 0;121} else {122/* All others: CLCDID 0x1f, indicating VGA */123s->sys_clcd = 0x1f00;124}125}
126
127static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,128unsigned size)129{
130arm_sysctl_state *s = (arm_sysctl_state *)opaque;131
132switch (offset) {133case 0x00: /* ID */134return s->sys_id;135case 0x04: /* SW */136/* General purpose hardware switches.137We don't have a useful way of exposing these to the user. */
138return 0;139case 0x08: /* LED */140return s->leds;141case 0x20: /* LOCK */142return s->lockval;143case 0x0c: /* OSC0 */144case 0x10: /* OSC1 */145case 0x14: /* OSC2 */146case 0x18: /* OSC3 */147case 0x1c: /* OSC4 */148case 0x24: /* 100HZ */149/* ??? Implement these. */150return 0;151case 0x28: /* CFGDATA1 */152return s->cfgdata1;153case 0x2c: /* CFGDATA2 */154return s->cfgdata2;155case 0x30: /* FLAGS */156return s->flags;157case 0x38: /* NVFLAGS */158return s->nvflags;159case 0x40: /* RESETCTL */160if (board_id(s) == BOARD_ID_VEXPRESS) {161/* reserved: RAZ/WI */162return 0;163}164return s->resetlevel;165case 0x44: /* PCICTL */166return 1;167case 0x48: /* MCI */168return s->sys_mci;169case 0x4c: /* FLASH */170return 0;171case 0x50: /* CLCD */172return s->sys_clcd;173case 0x54: /* CLCDSER */174return 0;175case 0x58: /* BOOTCS */176return 0;177case 0x5c: /* 24MHz */178return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24000000,179NANOSECONDS_PER_SECOND);180case 0x60: /* MISC */181return 0;182case 0x84: /* PROCID0 */183return s->proc_id;184case 0x88: /* PROCID1 */185return 0xff000000;186case 0x64: /* DMAPSR0 */187case 0x68: /* DMAPSR1 */188case 0x6c: /* DMAPSR2 */189case 0x70: /* IOSEL */190case 0x74: /* PLDCTL */191case 0x80: /* BUSID */192case 0x8c: /* OSCRESET0 */193case 0x90: /* OSCRESET1 */194case 0x94: /* OSCRESET2 */195case 0x98: /* OSCRESET3 */196case 0x9c: /* OSCRESET4 */197case 0xc0: /* SYS_TEST_OSC0 */198case 0xc4: /* SYS_TEST_OSC1 */199case 0xc8: /* SYS_TEST_OSC2 */200case 0xcc: /* SYS_TEST_OSC3 */201case 0xd0: /* SYS_TEST_OSC4 */202return 0;203case 0xa0: /* SYS_CFGDATA */204if (board_id(s) != BOARD_ID_VEXPRESS) {205goto bad_reg;206}207return s->sys_cfgdata;208case 0xa4: /* SYS_CFGCTRL */209if (board_id(s) != BOARD_ID_VEXPRESS) {210goto bad_reg;211}212return s->sys_cfgctrl;213case 0xa8: /* SYS_CFGSTAT */214if (board_id(s) != BOARD_ID_VEXPRESS) {215goto bad_reg;216}217return s->sys_cfgstat;218default:219bad_reg:220qemu_log_mask(LOG_GUEST_ERROR,221"arm_sysctl_read: Bad register offset 0x%x\n",222(int)offset);223return 0;224}225}
226
227/* SYS_CFGCTRL functions */
228#define SYS_CFG_OSC 1229#define SYS_CFG_VOLT 2230#define SYS_CFG_AMP 3231#define SYS_CFG_TEMP 4232#define SYS_CFG_RESET 5233#define SYS_CFG_SCC 6234#define SYS_CFG_MUXFPGA 7235#define SYS_CFG_SHUTDOWN 8236#define SYS_CFG_REBOOT 9237#define SYS_CFG_DVIMODE 11238#define SYS_CFG_POWER 12239#define SYS_CFG_ENERGY 13240
241/* SYS_CFGCTRL site field values */
242#define SYS_CFG_SITE_MB 0243#define SYS_CFG_SITE_DB1 1244#define SYS_CFG_SITE_DB2 2245
246/**
247* vexpress_cfgctrl_read:
248* @s: arm_sysctl_state pointer
249* @dcc, @function, @site, @position, @device: split out values from
250* SYS_CFGCTRL register
251* @val: pointer to where to put the read data on success
252*
253* Handle a VExpress SYS_CFGCTRL register read. On success, return true and
254* write the read value to *val. On failure, return false (and val may
255* or may not be written to).
256*/
257static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,258unsigned int function, unsigned int site,259unsigned int position, unsigned int device,260uint32_t *val)261{
262/* We don't support anything other than DCC 0, board stack position 0263* or sites other than motherboard/daughterboard:
264*/
265if (dcc != 0 || position != 0 ||266(site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {267goto cfgctrl_unimp;268}269
270switch (function) {271case SYS_CFG_VOLT:272if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) {273*val = s->db_voltage[device];274return true;275}276if (site == SYS_CFG_SITE_MB && device == 0) {277/* There is only one motherboard voltage sensor:278* VIO : 3.3V : bus voltage between mother and daughterboard
279*/
280*val = 3300000;281return true;282}283break;284case SYS_CFG_OSC:285if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {286/* motherboard clock */287*val = s->mb_clock[device];288return true;289}290if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {291/* daughterboard clock */292*val = s->db_clock[device];293return true;294}295break;296default:297break;298}299
300cfgctrl_unimp:301qemu_log_mask(LOG_UNIMP,302"arm_sysctl: Unimplemented SYS_CFGCTRL read of function "303"0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",304function, dcc, site, position, device);305return false;306}
307
308/**
309* vexpress_cfgctrl_write:
310* @s: arm_sysctl_state pointer
311* @dcc, @function, @site, @position, @device: split out values from
312* SYS_CFGCTRL register
313* @val: data to write
314*
315* Handle a VExpress SYS_CFGCTRL register write. On success, return true.
316* On failure, return false.
317*/
318static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,319unsigned int function, unsigned int site,320unsigned int position, unsigned int device,321uint32_t val)322{
323/* We don't support anything other than DCC 0, board stack position 0324* or sites other than motherboard/daughterboard:
325*/
326if (dcc != 0 || position != 0 ||327(site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {328goto cfgctrl_unimp;329}330
331switch (function) {332case SYS_CFG_OSC:333if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {334/* motherboard clock */335s->mb_clock[device] = val;336return true;337}338if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {339/* daughterboard clock */340s->db_clock[device] = val;341return true;342}343break;344case SYS_CFG_MUXFPGA:345if (site == SYS_CFG_SITE_MB && device == 0) {346/* Select whether video output comes from motherboard347* or daughterboard: log and ignore as QEMU doesn't
348* support this.
349*/
350qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output "351"not supported, ignoring\n");352return true;353}354break;355case SYS_CFG_SHUTDOWN:356if (site == SYS_CFG_SITE_MB && device == 0) {357qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);358return true;359}360break;361case SYS_CFG_REBOOT:362if (site == SYS_CFG_SITE_MB && device == 0) {363qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);364return true;365}366break;367case SYS_CFG_DVIMODE:368if (site == SYS_CFG_SITE_MB && device == 0) {369/* Selecting DVI mode is meaningless for QEMU: we will370* always display the output correctly according to the
371* pixel height/width programmed into the CLCD controller.
372*/
373return true;374}375default:376break;377}378
379cfgctrl_unimp:380qemu_log_mask(LOG_UNIMP,381"arm_sysctl: Unimplemented SYS_CFGCTRL write of function "382"0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",383function, dcc, site, position, device);384return false;385}
386
387static void arm_sysctl_write(void *opaque, hwaddr offset,388uint64_t val, unsigned size)389{
390arm_sysctl_state *s = (arm_sysctl_state *)opaque;391
392switch (offset) {393case 0x08: /* LED */394s->leds = val;395break;396case 0x0c: /* OSC0 */397case 0x10: /* OSC1 */398case 0x14: /* OSC2 */399case 0x18: /* OSC3 */400case 0x1c: /* OSC4 */401/* ??? */402break;403case 0x20: /* LOCK */404if (val == LOCK_VALUE)405s->lockval = val;406else407s->lockval = val & 0x7fff;408break;409case 0x28: /* CFGDATA1 */410/* ??? Need to implement this. */411s->cfgdata1 = val;412break;413case 0x2c: /* CFGDATA2 */414/* ??? Need to implement this. */415s->cfgdata2 = val;416break;417case 0x30: /* FLAGSSET */418s->flags |= val;419break;420case 0x34: /* FLAGSCLR */421s->flags &= ~val;422break;423case 0x38: /* NVFLAGSSET */424s->nvflags |= val;425break;426case 0x3c: /* NVFLAGSCLR */427s->nvflags &= ~val;428break;429case 0x40: /* RESETCTL */430switch (board_id(s)) {431case BOARD_ID_PB926:432if (s->lockval == LOCK_VALUE) {433s->resetlevel = val;434if (val & 0x100) {435qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);436}437}438break;439case BOARD_ID_PBX:440case BOARD_ID_PBA8:441if (s->lockval == LOCK_VALUE) {442s->resetlevel = val;443if (val & 0x04) {444qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);445}446}447break;448case BOARD_ID_VEXPRESS:449case BOARD_ID_EB:450default:451/* reserved: RAZ/WI */452break;453}454break;455case 0x44: /* PCICTL */456/* nothing to do. */457break;458case 0x4c: /* FLASH */459break;460case 0x50: /* CLCD */461switch (board_id(s)) {462case BOARD_ID_PB926:463/* On 926 bits 13:8 are R/O, bits 1:0 control464* the mux that defines how to interpret the PL110
465* graphics format, and other bits are r/w but we
466* don't implement them to do anything.
467*/
468s->sys_clcd &= 0x3f00;469s->sys_clcd |= val & ~0x3f00;470qemu_set_irq(s->pl110_mux_ctrl, val & 3);471break;472case BOARD_ID_EB:473/* The EB is the same except that there is no mux since474* the EB has a PL111.
475*/
476s->sys_clcd &= 0x3f00;477s->sys_clcd |= val & ~0x3f00;478break;479case BOARD_ID_PBA8:480case BOARD_ID_PBX:481/* On PBA8 and PBX bit 7 is r/w and all other bits482* are either r/o or RAZ/WI.
483*/
484s->sys_clcd &= (1 << 7);485s->sys_clcd |= val & ~(1 << 7);486break;487case BOARD_ID_VEXPRESS:488default:489/* On VExpress this register is unimplemented and will RAZ/WI */490break;491}492break;493case 0x54: /* CLCDSER */494case 0x64: /* DMAPSR0 */495case 0x68: /* DMAPSR1 */496case 0x6c: /* DMAPSR2 */497case 0x70: /* IOSEL */498case 0x74: /* PLDCTL */499case 0x80: /* BUSID */500case 0x84: /* PROCID0 */501case 0x88: /* PROCID1 */502case 0x8c: /* OSCRESET0 */503case 0x90: /* OSCRESET1 */504case 0x94: /* OSCRESET2 */505case 0x98: /* OSCRESET3 */506case 0x9c: /* OSCRESET4 */507break;508case 0xa0: /* SYS_CFGDATA */509if (board_id(s) != BOARD_ID_VEXPRESS) {510goto bad_reg;511}512s->sys_cfgdata = val;513return;514case 0xa4: /* SYS_CFGCTRL */515if (board_id(s) != BOARD_ID_VEXPRESS) {516goto bad_reg;517}518/* Undefined bits [19:18] are RAZ/WI, and writing to519* the start bit just triggers the action; it always reads
520* as zero.
521*/
522s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));523if (val & (1 << 31)) {524/* Start bit set -- actually do something */525unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);526unsigned int function = extract32(s->sys_cfgctrl, 20, 6);527unsigned int site = extract32(s->sys_cfgctrl, 16, 2);528unsigned int position = extract32(s->sys_cfgctrl, 12, 4);529unsigned int device = extract32(s->sys_cfgctrl, 0, 12);530s->sys_cfgstat = 1; /* complete */531if (s->sys_cfgctrl & (1 << 30)) {532if (!vexpress_cfgctrl_write(s, dcc, function, site, position,533device, s->sys_cfgdata)) {534s->sys_cfgstat |= 2; /* error */535}536} else {537uint32_t data;538if (!vexpress_cfgctrl_read(s, dcc, function, site, position,539device, &data)) {540s->sys_cfgstat |= 2; /* error */541} else {542s->sys_cfgdata = data;543}544}545}546s->sys_cfgctrl &= ~(1 << 31);547return;548case 0xa8: /* SYS_CFGSTAT */549if (board_id(s) != BOARD_ID_VEXPRESS) {550goto bad_reg;551}552s->sys_cfgstat = val & 3;553return;554default:555bad_reg:556qemu_log_mask(LOG_GUEST_ERROR,557"arm_sysctl_write: Bad register offset 0x%x\n",558(int)offset);559return;560}561}
562
563static const MemoryRegionOps arm_sysctl_ops = {564.read = arm_sysctl_read,565.write = arm_sysctl_write,566.endianness = DEVICE_NATIVE_ENDIAN,567};568
569static void arm_sysctl_gpio_set(void *opaque, int line, int level)570{
571arm_sysctl_state *s = (arm_sysctl_state *)opaque;572switch (line) {573case ARM_SYSCTL_GPIO_MMC_WPROT:574{575/* For PB926 and EB write-protect is bit 2 of SYS_MCI;576* for all later boards it is bit 1.
577*/
578int bit = 2;579if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {580bit = 4;581}582s->sys_mci &= ~bit;583if (level) {584s->sys_mci |= bit;585}586break;587}588case ARM_SYSCTL_GPIO_MMC_CARDIN:589s->sys_mci &= ~1;590if (level) {591s->sys_mci |= 1;592}593break;594}595}
596
597static void arm_sysctl_init(Object *obj)598{
599DeviceState *dev = DEVICE(obj);600SysBusDevice *sd = SYS_BUS_DEVICE(obj);601arm_sysctl_state *s = ARM_SYSCTL(obj);602
603memory_region_init_io(&s->iomem, OBJECT(dev), &arm_sysctl_ops, s,604"arm-sysctl", 0x1000);605sysbus_init_mmio(sd, &s->iomem);606qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2);607qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1);608}
609
610static void arm_sysctl_realize(DeviceState *d, Error **errp)611{
612arm_sysctl_state *s = ARM_SYSCTL(d);613
614s->db_clock = g_new0(uint32_t, s->db_num_clocks);615}
616
617static void arm_sysctl_finalize(Object *obj)618{
619arm_sysctl_state *s = ARM_SYSCTL(obj);620
621g_free(s->db_voltage);622g_free(s->db_clock);623g_free(s->db_clock_reset);624}
625
626static Property arm_sysctl_properties[] = {627DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),628DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),629/* Daughterboard power supply voltages (as reported via SYS_CFG) */630DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors,631db_voltage, qdev_prop_uint32, uint32_t),632/* Daughterboard clock reset values (as reported via SYS_CFG) */633DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks,634db_clock_reset, qdev_prop_uint32, uint32_t),635DEFINE_PROP_END_OF_LIST(),636};637
638static void arm_sysctl_class_init(ObjectClass *klass, void *data)639{
640DeviceClass *dc = DEVICE_CLASS(klass);641
642dc->realize = arm_sysctl_realize;643dc->reset = arm_sysctl_reset;644dc->vmsd = &vmstate_arm_sysctl;645device_class_set_props(dc, arm_sysctl_properties);646}
647
648static const TypeInfo arm_sysctl_info = {649.name = TYPE_ARM_SYSCTL,650.parent = TYPE_SYS_BUS_DEVICE,651.instance_size = sizeof(arm_sysctl_state),652.instance_init = arm_sysctl_init,653.instance_finalize = arm_sysctl_finalize,654.class_init = arm_sysctl_class_init,655};656
657static void arm_sysctl_register_types(void)658{
659type_register_static(&arm_sysctl_info);660}
661
662type_init(arm_sysctl_register_types)663