mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
hw/i2c: Implement NPCM7XX SMBus Module Single Mode
This commit implements the single-byte mode of the SMBus. Each Nuvoton SoC has 16 System Management Bus (SMBus). These buses compliant with SMBus and I2C protocol. This patch implements the single-byte mode of the SMBus. In this mode, the user sends or receives a byte each time. The SMBus device transmits it to the underlying i2c device and sends an interrupt back to the QEMU guest. Reviewed-by: Doug Evans<dje@google.com> Reviewed-by: Tyrong Ting<kfting@nuvoton.com> Signed-off-by: Hao Wu <wuhaotsh@google.com> Reviewed-by: Corey Minyard <cminyard@mvista.com> Message-id: 20210210220426.3577804-2-wuhaotsh@google.com Acked-by: Corey Minyard <cminyard@mvista.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -43,6 +43,7 @@ Supported devices
|
||||
* GPIO controller
|
||||
* Analog to Digital Converter (ADC)
|
||||
* Pulse Width Modulation (PWM)
|
||||
* SMBus controller (SMBF)
|
||||
|
||||
Missing devices
|
||||
---------------
|
||||
@@ -58,7 +59,6 @@ Missing devices
|
||||
|
||||
* Ethernet controllers (GMAC and EMC)
|
||||
* USB device (USBD)
|
||||
* SMBus controller (SMBF)
|
||||
* Peripheral SPI controller (PSPI)
|
||||
* SD/MMC host
|
||||
* PECI interface
|
||||
|
||||
+52
-16
@@ -102,6 +102,22 @@ enum NPCM7xxInterrupt {
|
||||
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
|
||||
NPCM7XX_EHCI_IRQ = 61,
|
||||
NPCM7XX_OHCI_IRQ = 62,
|
||||
NPCM7XX_SMBUS0_IRQ = 64,
|
||||
NPCM7XX_SMBUS1_IRQ,
|
||||
NPCM7XX_SMBUS2_IRQ,
|
||||
NPCM7XX_SMBUS3_IRQ,
|
||||
NPCM7XX_SMBUS4_IRQ,
|
||||
NPCM7XX_SMBUS5_IRQ,
|
||||
NPCM7XX_SMBUS6_IRQ,
|
||||
NPCM7XX_SMBUS7_IRQ,
|
||||
NPCM7XX_SMBUS8_IRQ,
|
||||
NPCM7XX_SMBUS9_IRQ,
|
||||
NPCM7XX_SMBUS10_IRQ,
|
||||
NPCM7XX_SMBUS11_IRQ,
|
||||
NPCM7XX_SMBUS12_IRQ,
|
||||
NPCM7XX_SMBUS13_IRQ,
|
||||
NPCM7XX_SMBUS14_IRQ,
|
||||
NPCM7XX_SMBUS15_IRQ,
|
||||
NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
|
||||
NPCM7XX_PWM1_IRQ, /* PWM module 1 */
|
||||
NPCM7XX_GPIO0_IRQ = 116,
|
||||
@@ -152,6 +168,26 @@ static const hwaddr npcm7xx_pwm_addr[] = {
|
||||
0xf0104000,
|
||||
};
|
||||
|
||||
/* Direct memory-mapped access to each SMBus Module. */
|
||||
static const hwaddr npcm7xx_smbus_addr[] = {
|
||||
0xf0080000,
|
||||
0xf0081000,
|
||||
0xf0082000,
|
||||
0xf0083000,
|
||||
0xf0084000,
|
||||
0xf0085000,
|
||||
0xf0086000,
|
||||
0xf0087000,
|
||||
0xf0088000,
|
||||
0xf0089000,
|
||||
0xf008a000,
|
||||
0xf008b000,
|
||||
0xf008c000,
|
||||
0xf008d000,
|
||||
0xf008e000,
|
||||
0xf008f000,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
hwaddr regs_addr;
|
||||
uint32_t unconnected_pins;
|
||||
@@ -353,6 +389,11 @@ static void npcm7xx_init(Object *obj)
|
||||
object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
|
||||
object_initialize_child(obj, "smbus[*]", &s->smbus[i],
|
||||
TYPE_NPCM7XX_SMBUS);
|
||||
}
|
||||
|
||||
object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
|
||||
object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
|
||||
|
||||
@@ -509,6 +550,17 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
npcm7xx_irq(s, NPCM7XX_GPIO0_IRQ + i));
|
||||
}
|
||||
|
||||
/* SMBus modules. Cannot fail. */
|
||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_smbus_addr) != ARRAY_SIZE(s->smbus));
|
||||
for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
|
||||
Object *obj = OBJECT(&s->smbus[i]);
|
||||
|
||||
sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_smbus_addr[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
|
||||
npcm7xx_irq(s, NPCM7XX_SMBUS0_IRQ + i));
|
||||
}
|
||||
|
||||
/* USB Host */
|
||||
object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
|
||||
&error_abort);
|
||||
@@ -576,22 +628,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
|
||||
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[0]", 0xf0080000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[1]", 0xf0081000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[2]", 0xf0082000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[3]", 0xf0083000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[4]", 0xf0084000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[5]", 0xf0085000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[6]", 0xf0086000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[7]", 0xf0087000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[8]", 0xf0088000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[9]", 0xf0089000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[10]", 0xf008a000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[11]", 0xf008b000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[12]", 0xf008c000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[13]", 0xf008d000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[14]", 0xf008e000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.smbus[15]", 0xf008f000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.espi", 0xf009f000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
|
||||
|
||||
@@ -9,6 +9,7 @@ i2c_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_i2c.c'))
|
||||
i2c_ss.add(when: 'CONFIG_IMX_I2C', if_true: files('imx_i2c.c'))
|
||||
i2c_ss.add(when: 'CONFIG_MPC_I2C', if_true: files('mpc_i2c.c'))
|
||||
i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c'))
|
||||
i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c'))
|
||||
i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c'))
|
||||
i2c_ss.add(when: 'CONFIG_VERSATILE_I2C', if_true: files('versatile_i2c.c'))
|
||||
i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c'))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,3 +14,14 @@ aspeed_i2c_bus_read(uint32_t busid, uint64_t offset, unsigned size, uint64_t val
|
||||
aspeed_i2c_bus_write(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
|
||||
aspeed_i2c_bus_send(const char *mode, int i, int count, uint8_t byte) "%s send %d/%d 0x%02x"
|
||||
aspeed_i2c_bus_recv(const char *mode, int i, int count, uint8_t byte) "%s recv %d/%d 0x%02x"
|
||||
|
||||
# npcm7xx_smbus.c
|
||||
|
||||
npcm7xx_smbus_read(const char *id, uint64_t offset, uint64_t value, unsigned size) "%s offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
|
||||
npcm7xx_smbus_write(const char *id, uint64_t offset, uint64_t value, unsigned size) "%s offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
|
||||
npcm7xx_smbus_start(const char *id, int success) "%s starting, success: %d"
|
||||
npcm7xx_smbus_send_address(const char *id, uint8_t addr, int recv, int success) "%s sending address: 0x%02x, recv: %d, success: %d"
|
||||
npcm7xx_smbus_send_byte(const char *id, uint8_t value, int success) "%s send byte: 0x%02x, success: %d"
|
||||
npcm7xx_smbus_recv_byte(const char *id, uint8_t value) "%s recv byte: 0x%02x"
|
||||
npcm7xx_smbus_stop(const char *id) "%s stopping"
|
||||
npcm7xx_smbus_nack(const char *id) "%s nacking"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "hw/adc/npcm7xx_adc.h"
|
||||
#include "hw/cpu/a9mpcore.h"
|
||||
#include "hw/gpio/npcm7xx_gpio.h"
|
||||
#include "hw/i2c/npcm7xx_smbus.h"
|
||||
#include "hw/mem/npcm7xx_mc.h"
|
||||
#include "hw/misc/npcm7xx_clk.h"
|
||||
#include "hw/misc/npcm7xx_gcr.h"
|
||||
@@ -85,6 +86,7 @@ typedef struct NPCM7xxState {
|
||||
NPCM7xxMCState mc;
|
||||
NPCM7xxRNGState rng;
|
||||
NPCM7xxGPIOState gpio[8];
|
||||
NPCM7xxSMBusState smbus[16];
|
||||
EHCISysBusState ehci;
|
||||
OHCISysBusState ohci;
|
||||
NPCM7xxFIUState fiu[2];
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Nuvoton NPCM7xx SMBus Module.
|
||||
*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
#ifndef NPCM7XX_SMBUS_H
|
||||
#define NPCM7XX_SMBUS_H
|
||||
|
||||
#include "exec/memory.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
/*
|
||||
* Number of addresses this module contains. Do not change this without
|
||||
* incrementing the version_id in the vmstate.
|
||||
*/
|
||||
#define NPCM7XX_SMBUS_NR_ADDRS 10
|
||||
|
||||
typedef enum NPCM7xxSMBusStatus {
|
||||
NPCM7XX_SMBUS_STATUS_IDLE,
|
||||
NPCM7XX_SMBUS_STATUS_SENDING,
|
||||
NPCM7XX_SMBUS_STATUS_RECEIVING,
|
||||
NPCM7XX_SMBUS_STATUS_NEGACK,
|
||||
NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE,
|
||||
NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK,
|
||||
} NPCM7xxSMBusStatus;
|
||||
|
||||
/*
|
||||
* struct NPCM7xxSMBusState - System Management Bus device state.
|
||||
* @bus: The underlying I2C Bus.
|
||||
* @irq: GIC interrupt line to fire on events (if enabled).
|
||||
* @sda: The serial data register.
|
||||
* @st: The status register.
|
||||
* @cst: The control status register.
|
||||
* @cst2: The control status register 2.
|
||||
* @cst3: The control status register 3.
|
||||
* @ctl1: The control register 1.
|
||||
* @ctl2: The control register 2.
|
||||
* @ctl3: The control register 3.
|
||||
* @ctl4: The control register 4.
|
||||
* @ctl5: The control register 5.
|
||||
* @addr: The SMBus module's own addresses on the I2C bus.
|
||||
* @scllt: The SCL low time register.
|
||||
* @sclht: The SCL high time register.
|
||||
* @status: The current status of the SMBus.
|
||||
*/
|
||||
typedef struct NPCM7xxSMBusState {
|
||||
SysBusDevice parent;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
I2CBus *bus;
|
||||
qemu_irq irq;
|
||||
|
||||
uint8_t sda;
|
||||
uint8_t st;
|
||||
uint8_t cst;
|
||||
uint8_t cst2;
|
||||
uint8_t cst3;
|
||||
uint8_t ctl1;
|
||||
uint8_t ctl2;
|
||||
uint8_t ctl3;
|
||||
uint8_t ctl4;
|
||||
uint8_t ctl5;
|
||||
uint8_t addr[NPCM7XX_SMBUS_NR_ADDRS];
|
||||
|
||||
uint8_t scllt;
|
||||
uint8_t sclht;
|
||||
|
||||
NPCM7xxSMBusStatus status;
|
||||
} NPCM7xxSMBusState;
|
||||
|
||||
#define TYPE_NPCM7XX_SMBUS "npcm7xx-smbus"
|
||||
#define NPCM7XX_SMBUS(obj) OBJECT_CHECK(NPCM7xxSMBusState, (obj), \
|
||||
TYPE_NPCM7XX_SMBUS)
|
||||
|
||||
#endif /* NPCM7XX_SMBUS_H */
|
||||
Reference in New Issue
Block a user