11599121bSAlistair Francis /*
21599121bSAlistair Francis * Register Definition API
31599121bSAlistair Francis *
41599121bSAlistair Francis * Copyright (c) 2016 Xilinx Inc.
51599121bSAlistair Francis * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
61599121bSAlistair Francis *
71599121bSAlistair Francis * This program is free software; you can redistribute it and/or modify it
81599121bSAlistair Francis * under the terms of the GNU General Public License as published by the
91599121bSAlistair Francis * Free Software Foundation; either version 2 of the License, or
101599121bSAlistair Francis * (at your option) any later version.
111599121bSAlistair Francis *
121599121bSAlistair Francis * This program is distributed in the hope that it will be useful, but WITHOUT
131599121bSAlistair Francis * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
141599121bSAlistair Francis * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
151599121bSAlistair Francis * for more details.
161599121bSAlistair Francis */
171599121bSAlistair Francis
181599121bSAlistair Francis #include "qemu/osdep.h"
191599121bSAlistair Francis #include "hw/register.h"
201599121bSAlistair Francis #include "qemu/log.h"
210b8fa32fSMarkus Armbruster #include "qemu/module.h"
221599121bSAlistair Francis
register_write_val(RegisterInfo * reg,uint64_t val)231599121bSAlistair Francis static inline void register_write_val(RegisterInfo *reg, uint64_t val)
241599121bSAlistair Francis {
251599121bSAlistair Francis g_assert(reg->data);
261599121bSAlistair Francis
271599121bSAlistair Francis switch (reg->data_size) {
281599121bSAlistair Francis case 1:
291599121bSAlistair Francis *(uint8_t *)reg->data = val;
301599121bSAlistair Francis break;
311599121bSAlistair Francis case 2:
321599121bSAlistair Francis *(uint16_t *)reg->data = val;
331599121bSAlistair Francis break;
341599121bSAlistair Francis case 4:
351599121bSAlistair Francis *(uint32_t *)reg->data = val;
361599121bSAlistair Francis break;
371599121bSAlistair Francis case 8:
381599121bSAlistair Francis *(uint64_t *)reg->data = val;
391599121bSAlistair Francis break;
401599121bSAlistair Francis default:
411599121bSAlistair Francis g_assert_not_reached();
421599121bSAlistair Francis }
431599121bSAlistair Francis }
441599121bSAlistair Francis
register_read_val(RegisterInfo * reg)451599121bSAlistair Francis static inline uint64_t register_read_val(RegisterInfo *reg)
461599121bSAlistair Francis {
471599121bSAlistair Francis switch (reg->data_size) {
481599121bSAlistair Francis case 1:
491599121bSAlistair Francis return *(uint8_t *)reg->data;
501599121bSAlistair Francis case 2:
511599121bSAlistair Francis return *(uint16_t *)reg->data;
521599121bSAlistair Francis case 4:
531599121bSAlistair Francis return *(uint32_t *)reg->data;
541599121bSAlistair Francis case 8:
551599121bSAlistair Francis return *(uint64_t *)reg->data;
561599121bSAlistair Francis default:
571599121bSAlistair Francis g_assert_not_reached();
581599121bSAlistair Francis }
591599121bSAlistair Francis return 0; /* unreachable */
601599121bSAlistair Francis }
611599121bSAlistair Francis
register_enabled_mask(int data_size,unsigned size)624729b3a4SPhilippe Mathieu-Daudé static inline uint64_t register_enabled_mask(int data_size, unsigned size)
634729b3a4SPhilippe Mathieu-Daudé {
644729b3a4SPhilippe Mathieu-Daudé if (data_size < size) {
654729b3a4SPhilippe Mathieu-Daudé size = data_size;
664729b3a4SPhilippe Mathieu-Daudé }
674729b3a4SPhilippe Mathieu-Daudé
684729b3a4SPhilippe Mathieu-Daudé return MAKE_64BIT_MASK(0, size * 8);
694729b3a4SPhilippe Mathieu-Daudé }
704729b3a4SPhilippe Mathieu-Daudé
register_write(RegisterInfo * reg,uint64_t val,uint64_t we,const char * prefix,bool debug)711599121bSAlistair Francis void register_write(RegisterInfo *reg, uint64_t val, uint64_t we,
721599121bSAlistair Francis const char *prefix, bool debug)
731599121bSAlistair Francis {
741599121bSAlistair Francis uint64_t old_val, new_val, test, no_w_mask;
751599121bSAlistair Francis const RegisterAccessInfo *ac;
761599121bSAlistair Francis
771599121bSAlistair Francis assert(reg);
781599121bSAlistair Francis
791599121bSAlistair Francis ac = reg->access;
801599121bSAlistair Francis
811599121bSAlistair Francis if (!ac || !ac->name) {
821599121bSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state "
83b3d2a429SXinhao Zhang "(written value: 0x%" PRIx64 ")\n", prefix, val);
841599121bSAlistair Francis return;
851599121bSAlistair Francis }
861599121bSAlistair Francis
871599121bSAlistair Francis old_val = reg->data ? register_read_val(reg) : ac->reset;
881599121bSAlistair Francis
891599121bSAlistair Francis test = (old_val ^ val) & ac->rsvd;
901599121bSAlistair Francis if (test) {
911599121bSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit"
92b3d2a429SXinhao Zhang "fields: 0x%" PRIx64 ")\n", prefix, test);
931599121bSAlistair Francis }
941599121bSAlistair Francis
951599121bSAlistair Francis test = val & ac->unimp;
961599121bSAlistair Francis if (test) {
971599121bSAlistair Francis qemu_log_mask(LOG_UNIMP,
98b3d2a429SXinhao Zhang "%s:%s writing 0x%" PRIx64 " to unimplemented bits:" \
99b3d2a429SXinhao Zhang " 0x%" PRIx64 "\n",
1001599121bSAlistair Francis prefix, reg->access->name, val, ac->unimp);
1011599121bSAlistair Francis }
1021599121bSAlistair Francis
1031599121bSAlistair Francis /* Create the no write mask based on the read only, write to clear and
1041599121bSAlistair Francis * reserved bit masks.
1051599121bSAlistair Francis */
1061599121bSAlistair Francis no_w_mask = ac->ro | ac->w1c | ac->rsvd | ~we;
1071599121bSAlistair Francis new_val = (val & ~no_w_mask) | (old_val & no_w_mask);
1081599121bSAlistair Francis new_val &= ~(val & ac->w1c);
1091599121bSAlistair Francis
1101599121bSAlistair Francis if (ac->pre_write) {
1111599121bSAlistair Francis new_val = ac->pre_write(reg, new_val);
1121599121bSAlistair Francis }
1131599121bSAlistair Francis
1141599121bSAlistair Francis if (debug) {
115b3d2a429SXinhao Zhang qemu_log("%s:%s: write of value 0x%" PRIx64 "\n", prefix, ac->name,
1161599121bSAlistair Francis new_val);
1171599121bSAlistair Francis }
1181599121bSAlistair Francis
1191599121bSAlistair Francis register_write_val(reg, new_val);
1201599121bSAlistair Francis
1211599121bSAlistair Francis if (ac->post_write) {
1221599121bSAlistair Francis ac->post_write(reg, new_val);
1231599121bSAlistair Francis }
1241599121bSAlistair Francis }
1251599121bSAlistair Francis
register_read(RegisterInfo * reg,uint64_t re,const char * prefix,bool debug)1261599121bSAlistair Francis uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix,
1271599121bSAlistair Francis bool debug)
1281599121bSAlistair Francis {
1291599121bSAlistair Francis uint64_t ret;
1301599121bSAlistair Francis const RegisterAccessInfo *ac;
1311599121bSAlistair Francis
1321599121bSAlistair Francis assert(reg);
1331599121bSAlistair Francis
1341599121bSAlistair Francis ac = reg->access;
1351599121bSAlistair Francis if (!ac || !ac->name) {
1361599121bSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state\n",
1371599121bSAlistair Francis prefix);
1381599121bSAlistair Francis return 0;
1391599121bSAlistair Francis }
1401599121bSAlistair Francis
1411599121bSAlistair Francis ret = reg->data ? register_read_val(reg) : ac->reset;
1421599121bSAlistair Francis
1431599121bSAlistair Francis register_write_val(reg, ret & ~(ac->cor & re));
1441599121bSAlistair Francis
1451599121bSAlistair Francis /* Mask based on the read enable size */
1461599121bSAlistair Francis ret &= re;
1471599121bSAlistair Francis
1481599121bSAlistair Francis if (ac->post_read) {
1491599121bSAlistair Francis ret = ac->post_read(reg, ret);
1501599121bSAlistair Francis }
1511599121bSAlistair Francis
1521599121bSAlistair Francis if (debug) {
153b3d2a429SXinhao Zhang qemu_log("%s:%s: read of value 0x%" PRIx64 "\n", prefix,
1541599121bSAlistair Francis ac->name, ret);
1551599121bSAlistair Francis }
1561599121bSAlistair Francis
1571599121bSAlistair Francis return ret;
1581599121bSAlistair Francis }
1591599121bSAlistair Francis
register_reset(RegisterInfo * reg)1601599121bSAlistair Francis void register_reset(RegisterInfo *reg)
1611599121bSAlistair Francis {
1624e5f0fb7SAlistair Francis const RegisterAccessInfo *ac;
1634e5f0fb7SAlistair Francis
1641599121bSAlistair Francis g_assert(reg);
1651599121bSAlistair Francis
1661599121bSAlistair Francis if (!reg->data || !reg->access) {
1671599121bSAlistair Francis return;
1681599121bSAlistair Francis }
1691599121bSAlistair Francis
1704e5f0fb7SAlistair Francis ac = reg->access;
1714e5f0fb7SAlistair Francis
1721599121bSAlistair Francis register_write_val(reg, reg->access->reset);
1734e5f0fb7SAlistair Francis
1744e5f0fb7SAlistair Francis if (ac->post_write) {
1754e5f0fb7SAlistair Francis ac->post_write(reg, reg->access->reset);
1764e5f0fb7SAlistair Francis }
1771599121bSAlistair Francis }
1780b73c9bbSAlistair Francis
register_write_memory(void * opaque,hwaddr addr,uint64_t value,unsigned size)1790b73c9bbSAlistair Francis void register_write_memory(void *opaque, hwaddr addr,
1800b73c9bbSAlistair Francis uint64_t value, unsigned size)
1810b73c9bbSAlistair Francis {
1820b73c9bbSAlistair Francis RegisterInfoArray *reg_array = opaque;
1830b73c9bbSAlistair Francis RegisterInfo *reg = NULL;
1840b73c9bbSAlistair Francis uint64_t we;
1850b73c9bbSAlistair Francis int i;
1860b73c9bbSAlistair Francis
1870b73c9bbSAlistair Francis for (i = 0; i < reg_array->num_elements; i++) {
1880b73c9bbSAlistair Francis if (reg_array->r[i]->access->addr == addr) {
1890b73c9bbSAlistair Francis reg = reg_array->r[i];
1900b73c9bbSAlistair Francis break;
1910b73c9bbSAlistair Francis }
1920b73c9bbSAlistair Francis }
1930b73c9bbSAlistair Francis
1940b73c9bbSAlistair Francis if (!reg) {
195016b4a93SPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, "%s: write to unimplemented register " \
196b3d2a429SXinhao Zhang "at address: 0x%" PRIx64 "\n", reg_array->prefix, addr);
1970b73c9bbSAlistair Francis return;
1980b73c9bbSAlistair Francis }
1990b73c9bbSAlistair Francis
2000b73c9bbSAlistair Francis /* Generate appropriate write enable mask */
2014729b3a4SPhilippe Mathieu-Daudé we = register_enabled_mask(reg->data_size, size);
2020b73c9bbSAlistair Francis
2030b73c9bbSAlistair Francis register_write(reg, value, we, reg_array->prefix,
2040b73c9bbSAlistair Francis reg_array->debug);
2050b73c9bbSAlistair Francis }
2060b73c9bbSAlistair Francis
register_read_memory(void * opaque,hwaddr addr,unsigned size)2070b73c9bbSAlistair Francis uint64_t register_read_memory(void *opaque, hwaddr addr,
2080b73c9bbSAlistair Francis unsigned size)
2090b73c9bbSAlistair Francis {
2100b73c9bbSAlistair Francis RegisterInfoArray *reg_array = opaque;
2110b73c9bbSAlistair Francis RegisterInfo *reg = NULL;
2120b73c9bbSAlistair Francis uint64_t read_val;
2134729b3a4SPhilippe Mathieu-Daudé uint64_t re;
2140b73c9bbSAlistair Francis int i;
2150b73c9bbSAlistair Francis
2160b73c9bbSAlistair Francis for (i = 0; i < reg_array->num_elements; i++) {
2170b73c9bbSAlistair Francis if (reg_array->r[i]->access->addr == addr) {
2180b73c9bbSAlistair Francis reg = reg_array->r[i];
2190b73c9bbSAlistair Francis break;
2200b73c9bbSAlistair Francis }
2210b73c9bbSAlistair Francis }
2220b73c9bbSAlistair Francis
2230b73c9bbSAlistair Francis if (!reg) {
224016b4a93SPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, "%s: read to unimplemented register " \
225b3d2a429SXinhao Zhang "at address: 0x%" PRIx64 "\n", reg_array->prefix, addr);
2260b73c9bbSAlistair Francis return 0;
2270b73c9bbSAlistair Francis }
2280b73c9bbSAlistair Francis
2294729b3a4SPhilippe Mathieu-Daudé /* Generate appropriate read enable mask */
2304729b3a4SPhilippe Mathieu-Daudé re = register_enabled_mask(reg->data_size, size);
2314729b3a4SPhilippe Mathieu-Daudé
2324729b3a4SPhilippe Mathieu-Daudé read_val = register_read(reg, re, reg_array->prefix,
2330b73c9bbSAlistair Francis reg_array->debug);
2340b73c9bbSAlistair Francis
2350b73c9bbSAlistair Francis return extract64(read_val, 0, size * 8);
2360b73c9bbSAlistair Francis }
23749e14ddbSPeter Crosthwaite
register_init_block(DeviceState * owner,const RegisterAccessInfo * rae,int num,RegisterInfo * ri,void * data,const MemoryRegionOps * ops,bool debug_enabled,uint64_t memory_size,size_t data_size_bits)238f08085f4SJoaquin de Andres static RegisterInfoArray *register_init_block(DeviceState *owner,
239a7422959SPeter Crosthwaite const RegisterAccessInfo *rae,
240a7422959SPeter Crosthwaite int num, RegisterInfo *ri,
241f08085f4SJoaquin de Andres void *data,
242a7422959SPeter Crosthwaite const MemoryRegionOps *ops,
243a7422959SPeter Crosthwaite bool debug_enabled,
244f08085f4SJoaquin de Andres uint64_t memory_size,
245f08085f4SJoaquin de Andres size_t data_size_bits)
246a7422959SPeter Crosthwaite {
247a7422959SPeter Crosthwaite const char *device_prefix = object_get_typename(OBJECT(owner));
248a7422959SPeter Crosthwaite RegisterInfoArray *r_array = g_new0(RegisterInfoArray, 1);
249f08085f4SJoaquin de Andres int data_size = data_size_bits >> 3;
250a7422959SPeter Crosthwaite int i;
251a7422959SPeter Crosthwaite
252a7422959SPeter Crosthwaite r_array->r = g_new0(RegisterInfo *, num);
253a7422959SPeter Crosthwaite r_array->num_elements = num;
254a7422959SPeter Crosthwaite r_array->debug = debug_enabled;
255a7422959SPeter Crosthwaite r_array->prefix = device_prefix;
256a7422959SPeter Crosthwaite
257a7422959SPeter Crosthwaite for (i = 0; i < num; i++) {
258f08085f4SJoaquin de Andres int index = rae[i].addr / data_size;
259a7422959SPeter Crosthwaite RegisterInfo *r = &ri[index];
260a7422959SPeter Crosthwaite
261e8a612b7SAlistair Francis /* Init the register, this will zero it. */
262e8a612b7SAlistair Francis object_initialize((void *)r, sizeof(*r), TYPE_REGISTER);
263e8a612b7SAlistair Francis
264e8a612b7SAlistair Francis /* Set the properties of the register */
265e8a612b7SAlistair Francis r->data = data + data_size * index;
266e8a612b7SAlistair Francis r->data_size = data_size;
267e8a612b7SAlistair Francis r->access = &rae[i];
268e8a612b7SAlistair Francis r->opaque = owner;
269a7422959SPeter Crosthwaite
270a7422959SPeter Crosthwaite r_array->r[i] = r;
271a7422959SPeter Crosthwaite }
272a7422959SPeter Crosthwaite
273a7422959SPeter Crosthwaite memory_region_init_io(&r_array->mem, OBJECT(owner), ops, r_array,
274a7422959SPeter Crosthwaite device_prefix, memory_size);
275a7422959SPeter Crosthwaite
276a7422959SPeter Crosthwaite return r_array;
277a7422959SPeter Crosthwaite }
278a7422959SPeter Crosthwaite
register_init_block8(DeviceState * owner,const RegisterAccessInfo * rae,int num,RegisterInfo * ri,uint8_t * data,const MemoryRegionOps * ops,bool debug_enabled,uint64_t memory_size)279f08085f4SJoaquin de Andres RegisterInfoArray *register_init_block8(DeviceState *owner,
280f08085f4SJoaquin de Andres const RegisterAccessInfo *rae,
281f08085f4SJoaquin de Andres int num, RegisterInfo *ri,
282f08085f4SJoaquin de Andres uint8_t *data,
283f08085f4SJoaquin de Andres const MemoryRegionOps *ops,
284f08085f4SJoaquin de Andres bool debug_enabled,
285f08085f4SJoaquin de Andres uint64_t memory_size)
286f08085f4SJoaquin de Andres {
287f08085f4SJoaquin de Andres return register_init_block(owner, rae, num, ri, (void *)
288f08085f4SJoaquin de Andres data, ops, debug_enabled, memory_size, 8);
289f08085f4SJoaquin de Andres }
290f08085f4SJoaquin de Andres
register_init_block32(DeviceState * owner,const RegisterAccessInfo * rae,int num,RegisterInfo * ri,uint32_t * data,const MemoryRegionOps * ops,bool debug_enabled,uint64_t memory_size)291f08085f4SJoaquin de Andres RegisterInfoArray *register_init_block32(DeviceState *owner,
292f08085f4SJoaquin de Andres const RegisterAccessInfo *rae,
293f08085f4SJoaquin de Andres int num, RegisterInfo *ri,
294f08085f4SJoaquin de Andres uint32_t *data,
295f08085f4SJoaquin de Andres const MemoryRegionOps *ops,
296f08085f4SJoaquin de Andres bool debug_enabled,
297f08085f4SJoaquin de Andres uint64_t memory_size)
298f08085f4SJoaquin de Andres {
299f08085f4SJoaquin de Andres return register_init_block(owner, rae, num, ri, (void *)
300f08085f4SJoaquin de Andres data, ops, debug_enabled, memory_size, 32);
301f08085f4SJoaquin de Andres }
302f08085f4SJoaquin de Andres
register_init_block64(DeviceState * owner,const RegisterAccessInfo * rae,int num,RegisterInfo * ri,uint64_t * data,const MemoryRegionOps * ops,bool debug_enabled,uint64_t memory_size)303*4d63ef20SJoe Komlodi RegisterInfoArray *register_init_block64(DeviceState *owner,
304*4d63ef20SJoe Komlodi const RegisterAccessInfo *rae,
305*4d63ef20SJoe Komlodi int num, RegisterInfo *ri,
306*4d63ef20SJoe Komlodi uint64_t *data,
307*4d63ef20SJoe Komlodi const MemoryRegionOps *ops,
308*4d63ef20SJoe Komlodi bool debug_enabled,
309*4d63ef20SJoe Komlodi uint64_t memory_size)
310*4d63ef20SJoe Komlodi {
311*4d63ef20SJoe Komlodi return register_init_block(owner, rae, num, ri, (void *)
312*4d63ef20SJoe Komlodi data, ops, debug_enabled, memory_size, 64);
313*4d63ef20SJoe Komlodi }
314*4d63ef20SJoe Komlodi
register_finalize_block(RegisterInfoArray * r_array)315a7422959SPeter Crosthwaite void register_finalize_block(RegisterInfoArray *r_array)
316a7422959SPeter Crosthwaite {
317a7422959SPeter Crosthwaite object_unparent(OBJECT(&r_array->mem));
318a7422959SPeter Crosthwaite g_free(r_array->r);
319a7422959SPeter Crosthwaite g_free(r_array);
320a7422959SPeter Crosthwaite }
321a7422959SPeter Crosthwaite
register_class_init(ObjectClass * oc,void * data)322a6e3707eSThomas Huth static void register_class_init(ObjectClass *oc, void *data)
323a6e3707eSThomas Huth {
324a6e3707eSThomas Huth DeviceClass *dc = DEVICE_CLASS(oc);
325a6e3707eSThomas Huth
326a6e3707eSThomas Huth /* Reason: needs to be wired up to work */
327e90f2a8cSEduardo Habkost dc->user_creatable = false;
328a6e3707eSThomas Huth }
329a6e3707eSThomas Huth
33049e14ddbSPeter Crosthwaite static const TypeInfo register_info = {
33149e14ddbSPeter Crosthwaite .name = TYPE_REGISTER,
33249e14ddbSPeter Crosthwaite .parent = TYPE_DEVICE,
333a6e3707eSThomas Huth .class_init = register_class_init,
334e8a612b7SAlistair Francis .instance_size = sizeof(RegisterInfo),
33549e14ddbSPeter Crosthwaite };
33649e14ddbSPeter Crosthwaite
register_register_types(void)33749e14ddbSPeter Crosthwaite static void register_register_types(void)
33849e14ddbSPeter Crosthwaite {
33949e14ddbSPeter Crosthwaite type_register_static(®ister_info);
34049e14ddbSPeter Crosthwaite }
34149e14ddbSPeter Crosthwaite
34249e14ddbSPeter Crosthwaite type_init(register_register_types)
343