[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH v1 08/12] hw/misc: AXP221 PMU Emulation
From: |
qianfanguijin |
Subject: |
[RFC PATCH v1 08/12] hw/misc: AXP221 PMU Emulation |
Date: |
Thu, 2 Mar 2023 19:40:57 +0800 |
From: qianfan Zhao <qianfanguijin@163.com>
This patch adds minimal support for AXP-221 PMU and connect it to
bananapi M2U board.
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
---
hw/arm/Kconfig | 1 +
hw/arm/bananapi_m2u.c | 5 ++
hw/misc/Kconfig | 4 +
hw/misc/axp221.c | 196 ++++++++++++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
hw/misc/trace-events | 5 ++
6 files changed, 212 insertions(+)
create mode 100644 hw/misc/axp221.c
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 8eabedce43..5d2c10cb18 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -347,6 +347,7 @@ config ALLWINNER_H3
config ALLWINNER_R40
bool
select ALLWINNER_A10_PIT
+ select AXP221_PMU
select SERIAL
select ARM_TIMER
select ARM_GIC
diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c
index 1b6241719d..bdee12efd3 100644
--- a/hw/arm/bananapi_m2u.c
+++ b/hw/arm/bananapi_m2u.c
@@ -22,6 +22,7 @@
#include "exec/address-spaces.h"
#include "qapi/error.h"
#include "hw/boards.h"
+#include "hw/i2c/i2c.h"
#include "hw/qdev-properties.h"
#include "hw/arm/allwinner-r40.h"
@@ -91,6 +92,10 @@ static void bpim2u_init(MachineState *machine)
&bootroom_loaded);
mmc_attach_drive(r40, &r40->mmc3, 3, false, NULL);
+ /* Connect AXP221 */
+ i2c = I2C_BUS(qdev_get_child_bus(DEVICE(&r40->i2c0), "i2c"));
+ i2c_slave_create_simple(i2c, "axp221_pmu", 0x34);
+
/* SDRAM */
memory_region_add_subregion(get_system_memory(),
r40->memmap[AW_R40_DEV_SDRAM],
machine->ram);
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 2ef5781ef8..f66ac390b1 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -180,4 +180,8 @@ config AXP209_PMU
bool
depends on I2C
+config AXP221_PMU
+ bool
+ depends on I2C
+
source macio/Kconfig
diff --git a/hw/misc/axp221.c b/hw/misc/axp221.c
new file mode 100644
index 0000000000..47784bb085
--- /dev/null
+++ b/hw/misc/axp221.c
@@ -0,0 +1,196 @@
+/*
+ * AXP-221/221s PMU Emulation
+ *
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/bitops.h"
+#include "trace.h"
+#include "hw/i2c/i2c.h"
+#include "migration/vmstate.h"
+
+#define TYPE_AXP221_PMU "axp221_pmu"
+
+#define AXP221(obj) \
+ OBJECT_CHECK(AXP221I2CState, (obj), TYPE_AXP221_PMU)
+
+#define NR_REGS 0xff
+
+/* A simple I2C slave which returns values of ID or CNT register. */
+typedef struct AXP221I2CState {
+ /*< private >*/
+ I2CSlave i2c;
+ /*< public >*/
+ uint8_t regs[NR_REGS]; /* peripheral registers */
+ uint8_t ptr; /* current register index */
+ uint8_t count; /* counter used for tx/rx */
+} AXP221I2CState;
+
+#define AXP221_PWR_STATUS_ACIN_PRESENT BIT(7)
+#define AXP221_PWR_STATUS_ACIN_AVAIL BIT(6)
+#define AXP221_PWR_STATUS_VBUS_PRESENT BIT(5)
+#define AXP221_PWR_STATUS_VBUS_USED BIT(4)
+#define AXP221_PWR_STATUS_BAT_CHARGING BIT(2)
+#define AXP221_PWR_STATUS_ACIN_VBUS_POWERED BIT(1)
+
+/* Reset all counters and load ID register */
+static void axp221_reset_enter(Object *obj, ResetType type)
+{
+ AXP221I2CState *s = AXP221(obj);
+
+ memset(s->regs, 0, NR_REGS);
+ s->ptr = 0;
+ s->count = 0;
+
+ /* input power status register */
+ s->regs[0x00] = AXP221_PWR_STATUS_ACIN_PRESENT
+ | AXP221_PWR_STATUS_ACIN_AVAIL
+ | AXP221_PWR_STATUS_ACIN_VBUS_POWERED;
+
+ s->regs[0x01] = 0x00; /* no battery is connected */
+
+ /* CHIPID register, no documented on datasheet, but it is checked in
+ * u-boot spl. I had read it from AXP221s and got 0x06 value.
+ * So leave 06h here.
+ */
+ s->regs[0x03] = 0x06;
+
+ s->regs[0x10] = 0xbf;
+ s->regs[0x13] = 0x01;
+ s->regs[0x30] = 0x60;
+ s->regs[0x31] = 0x03;
+ s->regs[0x32] = 0x43;
+ s->regs[0x33] = 0xc6;
+ s->regs[0x34] = 0x45;
+ s->regs[0x35] = 0x0e;
+ s->regs[0x36] = 0x5d;
+ s->regs[0x37] = 0x08;
+ s->regs[0x38] = 0xa5;
+ s->regs[0x39] = 0x1f;
+ s->regs[0x3c] = 0xfc;
+ s->regs[0x3d] = 0x16;
+ s->regs[0x80] = 0x80;
+ s->regs[0x82] = 0xe0;
+ s->regs[0x84] = 0x32;
+ s->regs[0x8f] = 0x01;
+
+ s->regs[0x90] = 0x07;
+ s->regs[0x91] = 0x1f;
+ s->regs[0x92] = 0x07;
+ s->regs[0x93] = 0x1f;
+
+ s->regs[0x40] = 0xd8;
+ s->regs[0x41] = 0xff;
+ s->regs[0x42] = 0x03;
+ s->regs[0x43] = 0x03;
+
+ s->regs[0xb8] = 0xc0;
+ s->regs[0xb9] = 0x64;
+ s->regs[0xe6] = 0xa0;
+}
+
+/* Handle events from master. */
+static int axp221_event(I2CSlave *i2c, enum i2c_event event)
+{
+ AXP221I2CState *s = AXP221(i2c);
+
+ s->count = 0;
+
+ return 0;
+}
+
+/* Called when master requests read */
+static uint8_t axp221_rx(I2CSlave *i2c)
+{
+ AXP221I2CState *s = AXP221(i2c);
+ uint8_t ret = 0xff;
+
+ if (s->ptr < NR_REGS) {
+ ret = s->regs[s->ptr];
+ trace_axp221_rx(s->ptr, ret);
+ s->ptr++;
+ }
+
+ return ret;
+}
+
+/*
+ * Called when master sends write.
+ * Update ptr with byte 0, then perform write with second byte.
+ */
+static int axp221_tx(I2CSlave *i2c, uint8_t data)
+{
+ AXP221I2CState *s = AXP221(i2c);
+
+ if (s->count == 0) {
+ /* Store register address */
+ s->ptr = data;
+ s->count++;
+ trace_axp221_select(data);
+ } else {
+ trace_axp221_tx(s->ptr, data);
+ s->regs[s->ptr++] = data;
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_axp221 = {
+ .name = TYPE_AXP221_PMU,
+ .version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8_ARRAY(regs, AXP221I2CState, NR_REGS),
+ VMSTATE_UINT8(count, AXP221I2CState),
+ VMSTATE_UINT8(ptr, AXP221I2CState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void axp221_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc);
+ ResettableClass *rc = RESETTABLE_CLASS(oc);
+
+ rc->phases.enter = axp221_reset_enter;
+ dc->vmsd = &vmstate_axp221;
+ isc->event = axp221_event;
+ isc->recv = axp221_rx;
+ isc->send = axp221_tx;
+}
+
+static const TypeInfo axp221_info = {
+ .name = TYPE_AXP221_PMU,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(AXP221I2CState),
+ .class_init = axp221_class_init
+};
+
+static void axp221_register_devices(void)
+{
+ type_register_static(&axp221_info);
+}
+
+type_init(axp221_register_devices);
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index b19b44841a..6b81670641 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -46,6 +46,7 @@ softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true:
files('allwinner-h3-sysctrl
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sid.c'))
softmmu_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true:
files('allwinner-r40-ccu.c'))
softmmu_ss.add(when: 'CONFIG_AXP209_PMU', if_true: files('axp209.c'))
+softmmu_ss.add(when: 'CONFIG_AXP221_PMU', if_true: files('axp221.c'))
softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
softmmu_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c'))
softmmu_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c'))
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index c47876a902..63b072d2d8 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -28,6 +28,11 @@ axp209_rx(uint8_t reg, uint8_t data) "Read reg 0x%" PRIx8 "
: 0x%" PRIx8
axp209_select(uint8_t reg) "Accessing reg 0x%" PRIx8
axp209_tx(uint8_t reg, uint8_t data) "Write reg 0x%" PRIx8 " : 0x%" PRIx8
+# axp221.c
+axp221_rx(uint8_t reg, uint8_t data) "Read reg 0x%" PRIx8 " : 0x%" PRIx8
+axp221_select(uint8_t reg) "Accessing reg 0x%" PRIx8
+axp221_tx(uint8_t reg, uint8_t data) "Write reg 0x%" PRIx8 " : 0x%" PRIx8
+
# eccmemctl.c
ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x"
ecc_mem_writel_mdr(uint32_t val) "Write memory delay 0x%08x"
--
2.25.1
- [RFC PATCH v1 00/12] *** Add allwinner R40 device support ***, qianfanguijin, 2023/03/02
- [RFC PATCH v1 10/12] hw: sd: allwinner-sdhost: Add sun50i-a64 SoC support, qianfanguijin, 2023/03/02
- [RFC PATCH v1 04/12] hw: arm: Add bananapi M2-Ultra and allwinner-r40 support, qianfanguijin, 2023/03/02
- [RFC PATCH v1 06/12] hw: allwinner-r40: Complete uart devices, qianfanguijin, 2023/03/02
- [RFC PATCH v1 03/12] hw: arm: allwinner-h3: Fix and complete H3 i2c devices, qianfanguijin, 2023/03/02
- [RFC PATCH v1 01/12] hw: allwinner-i2c: Make the trace message more readable, qianfanguijin, 2023/03/02
- [RFC PATCH v1 02/12] hw: allwinner-i2c: Fix TWI_CNTR_INT_FLAG on SUN6i SoCs, qianfanguijin, 2023/03/02
- [RFC PATCH v1 09/12] hw/arm/allwinner-r40: add SDRAM controller device, qianfanguijin, 2023/03/02
- [RFC PATCH v1 05/12] hw/arm/allwinner-r40: add Clock Control Unit, qianfanguijin, 2023/03/02
- [RFC PATCH v1 07/12] hw: arm: allwinner-r40: Add 5 TWI controllers, qianfanguijin, 2023/03/02
- [RFC PATCH v1 08/12] hw/misc: AXP221 PMU Emulation,
qianfanguijin <=
- Re: [RFC PATCH v1 00/12] *** Add allwinner R40 device support ***, Peter Maydell, 2023/03/06
- Re: [RFC PATCH v1 00/12] *** Add allwinner R40 device support ***, Niek Linnenbank, 2023/03/08