19be8a82cSStrahinja Jankovic /* 29be8a82cSStrahinja Jankovic * Allwinner I2C Bus Serial Interface Emulation 39be8a82cSStrahinja Jankovic * 49be8a82cSStrahinja Jankovic * Copyright (C) 2022 Strahinja Jankovic <strahinja.p.jankovic@gmail.com> 59be8a82cSStrahinja Jankovic * 69be8a82cSStrahinja Jankovic * This file is derived from IMX I2C controller, 79be8a82cSStrahinja Jankovic * by Jean-Christophe DUBOIS . 89be8a82cSStrahinja Jankovic * 99be8a82cSStrahinja Jankovic * This program is free software; you can redistribute it and/or modify it 109be8a82cSStrahinja Jankovic * under the terms of the GNU General Public License as published by the 119be8a82cSStrahinja Jankovic * Free Software Foundation; either version 2 of the License, or 129be8a82cSStrahinja Jankovic * (at your option) any later version. 139be8a82cSStrahinja Jankovic * 149be8a82cSStrahinja Jankovic * This program is distributed in the hope that it will be useful, but WITHOUT 159be8a82cSStrahinja Jankovic * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 169be8a82cSStrahinja Jankovic * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 179be8a82cSStrahinja Jankovic * for more details. 189be8a82cSStrahinja Jankovic * 199be8a82cSStrahinja Jankovic * You should have received a copy of the GNU General Public License along 209be8a82cSStrahinja Jankovic * with this program; if not, see <http://www.gnu.org/licenses/>. 219be8a82cSStrahinja Jankovic * 229be8a82cSStrahinja Jankovic * SPDX-License-Identifier: MIT 239be8a82cSStrahinja Jankovic */ 249be8a82cSStrahinja Jankovic 259be8a82cSStrahinja Jankovic #include "qemu/osdep.h" 269be8a82cSStrahinja Jankovic #include "hw/i2c/allwinner-i2c.h" 279be8a82cSStrahinja Jankovic #include "hw/irq.h" 289be8a82cSStrahinja Jankovic #include "migration/vmstate.h" 299be8a82cSStrahinja Jankovic #include "hw/i2c/i2c.h" 309be8a82cSStrahinja Jankovic #include "qemu/log.h" 319be8a82cSStrahinja Jankovic #include "trace.h" 329be8a82cSStrahinja Jankovic #include "qemu/module.h" 339be8a82cSStrahinja Jankovic 349be8a82cSStrahinja Jankovic /* Allwinner I2C memory map */ 359be8a82cSStrahinja Jankovic #define TWI_ADDR_REG 0x00 /* slave address register */ 369be8a82cSStrahinja Jankovic #define TWI_XADDR_REG 0x04 /* extended slave address register */ 379be8a82cSStrahinja Jankovic #define TWI_DATA_REG 0x08 /* data register */ 389be8a82cSStrahinja Jankovic #define TWI_CNTR_REG 0x0c /* control register */ 399be8a82cSStrahinja Jankovic #define TWI_STAT_REG 0x10 /* status register */ 409be8a82cSStrahinja Jankovic #define TWI_CCR_REG 0x14 /* clock control register */ 419be8a82cSStrahinja Jankovic #define TWI_SRST_REG 0x18 /* software reset register */ 429be8a82cSStrahinja Jankovic #define TWI_EFR_REG 0x1c /* enhance feature register */ 439be8a82cSStrahinja Jankovic #define TWI_LCR_REG 0x20 /* line control register */ 449be8a82cSStrahinja Jankovic 459be8a82cSStrahinja Jankovic /* Used only in slave mode, do not set */ 469be8a82cSStrahinja Jankovic #define TWI_ADDR_RESET 0 479be8a82cSStrahinja Jankovic #define TWI_XADDR_RESET 0 489be8a82cSStrahinja Jankovic 499be8a82cSStrahinja Jankovic /* Data register */ 509be8a82cSStrahinja Jankovic #define TWI_DATA_MASK 0xFF 519be8a82cSStrahinja Jankovic #define TWI_DATA_RESET 0 529be8a82cSStrahinja Jankovic 539be8a82cSStrahinja Jankovic /* Control register */ 549be8a82cSStrahinja Jankovic #define TWI_CNTR_INT_EN (1 << 7) 559be8a82cSStrahinja Jankovic #define TWI_CNTR_BUS_EN (1 << 6) 569be8a82cSStrahinja Jankovic #define TWI_CNTR_M_STA (1 << 5) 579be8a82cSStrahinja Jankovic #define TWI_CNTR_M_STP (1 << 4) 589be8a82cSStrahinja Jankovic #define TWI_CNTR_INT_FLAG (1 << 3) 599be8a82cSStrahinja Jankovic #define TWI_CNTR_A_ACK (1 << 2) 609be8a82cSStrahinja Jankovic #define TWI_CNTR_MASK 0xFC 619be8a82cSStrahinja Jankovic #define TWI_CNTR_RESET 0 629be8a82cSStrahinja Jankovic 639be8a82cSStrahinja Jankovic /* Status register */ 649be8a82cSStrahinja Jankovic #define TWI_STAT_MASK 0xF8 659be8a82cSStrahinja Jankovic #define TWI_STAT_RESET 0xF8 669be8a82cSStrahinja Jankovic 679be8a82cSStrahinja Jankovic /* Clock register */ 689be8a82cSStrahinja Jankovic #define TWI_CCR_CLK_M_MASK 0x78 699be8a82cSStrahinja Jankovic #define TWI_CCR_CLK_N_MASK 0x07 709be8a82cSStrahinja Jankovic #define TWI_CCR_MASK 0x7F 719be8a82cSStrahinja Jankovic #define TWI_CCR_RESET 0 729be8a82cSStrahinja Jankovic 739be8a82cSStrahinja Jankovic /* Soft reset */ 749be8a82cSStrahinja Jankovic #define TWI_SRST_MASK 0x01 759be8a82cSStrahinja Jankovic #define TWI_SRST_RESET 0 769be8a82cSStrahinja Jankovic 779be8a82cSStrahinja Jankovic /* Enhance feature */ 789be8a82cSStrahinja Jankovic #define TWI_EFR_MASK 0x03 799be8a82cSStrahinja Jankovic #define TWI_EFR_RESET 0 809be8a82cSStrahinja Jankovic 819be8a82cSStrahinja Jankovic /* Line control */ 829be8a82cSStrahinja Jankovic #define TWI_LCR_SCL_STATE (1 << 5) 839be8a82cSStrahinja Jankovic #define TWI_LCR_SDA_STATE (1 << 4) 849be8a82cSStrahinja Jankovic #define TWI_LCR_SCL_CTL (1 << 3) 859be8a82cSStrahinja Jankovic #define TWI_LCR_SCL_CTL_EN (1 << 2) 869be8a82cSStrahinja Jankovic #define TWI_LCR_SDA_CTL (1 << 1) 879be8a82cSStrahinja Jankovic #define TWI_LCR_SDA_CTL_EN (1 << 0) 889be8a82cSStrahinja Jankovic #define TWI_LCR_MASK 0x3F 899be8a82cSStrahinja Jankovic #define TWI_LCR_RESET 0x3A 909be8a82cSStrahinja Jankovic 919be8a82cSStrahinja Jankovic /* Status value in STAT register is shifted by 3 bits */ 929be8a82cSStrahinja Jankovic #define TWI_STAT_SHIFT 3 939be8a82cSStrahinja Jankovic #define STAT_FROM_STA(x) ((x) << TWI_STAT_SHIFT) 949be8a82cSStrahinja Jankovic #define STAT_TO_STA(x) ((x) >> TWI_STAT_SHIFT) 959be8a82cSStrahinja Jankovic 969be8a82cSStrahinja Jankovic enum { 979be8a82cSStrahinja Jankovic STAT_BUS_ERROR = 0, 989be8a82cSStrahinja Jankovic /* Master mode */ 999be8a82cSStrahinja Jankovic STAT_M_STA_TX, 1009be8a82cSStrahinja Jankovic STAT_M_RSTA_TX, 1019be8a82cSStrahinja Jankovic STAT_M_ADDR_WR_ACK, 1029be8a82cSStrahinja Jankovic STAT_M_ADDR_WR_NACK, 1039be8a82cSStrahinja Jankovic STAT_M_DATA_TX_ACK, 1049be8a82cSStrahinja Jankovic STAT_M_DATA_TX_NACK, 1059be8a82cSStrahinja Jankovic STAT_M_ARB_LOST, 1069be8a82cSStrahinja Jankovic STAT_M_ADDR_RD_ACK, 1079be8a82cSStrahinja Jankovic STAT_M_ADDR_RD_NACK, 1089be8a82cSStrahinja Jankovic STAT_M_DATA_RX_ACK, 1099be8a82cSStrahinja Jankovic STAT_M_DATA_RX_NACK, 1109be8a82cSStrahinja Jankovic /* Slave mode */ 1119be8a82cSStrahinja Jankovic STAT_S_ADDR_WR_ACK, 1129be8a82cSStrahinja Jankovic STAT_S_ARB_LOST_AW_ACK, 1139be8a82cSStrahinja Jankovic STAT_S_GCA_ACK, 1149be8a82cSStrahinja Jankovic STAT_S_ARB_LOST_GCA_ACK, 1159be8a82cSStrahinja Jankovic STAT_S_DATA_RX_SA_ACK, 1169be8a82cSStrahinja Jankovic STAT_S_DATA_RX_SA_NACK, 1179be8a82cSStrahinja Jankovic STAT_S_DATA_RX_GCA_ACK, 1189be8a82cSStrahinja Jankovic STAT_S_DATA_RX_GCA_NACK, 1199be8a82cSStrahinja Jankovic STAT_S_STP_RSTA, 1209be8a82cSStrahinja Jankovic STAT_S_ADDR_RD_ACK, 1219be8a82cSStrahinja Jankovic STAT_S_ARB_LOST_AR_ACK, 1229be8a82cSStrahinja Jankovic STAT_S_DATA_TX_ACK, 1239be8a82cSStrahinja Jankovic STAT_S_DATA_TX_NACK, 1249be8a82cSStrahinja Jankovic STAT_S_LB_TX_ACK, 1259be8a82cSStrahinja Jankovic /* Master mode, 10-bit */ 1269be8a82cSStrahinja Jankovic STAT_M_2ND_ADDR_WR_ACK, 1279be8a82cSStrahinja Jankovic STAT_M_2ND_ADDR_WR_NACK, 1289be8a82cSStrahinja Jankovic /* Idle */ 1299be8a82cSStrahinja Jankovic STAT_IDLE = 0x1f 1309be8a82cSStrahinja Jankovic } TWI_STAT_STA; 1319be8a82cSStrahinja Jankovic 1329be8a82cSStrahinja Jankovic static const char *allwinner_i2c_get_regname(unsigned offset) 1339be8a82cSStrahinja Jankovic { 1349be8a82cSStrahinja Jankovic switch (offset) { 1359be8a82cSStrahinja Jankovic case TWI_ADDR_REG: 1369be8a82cSStrahinja Jankovic return "ADDR"; 1379be8a82cSStrahinja Jankovic case TWI_XADDR_REG: 1389be8a82cSStrahinja Jankovic return "XADDR"; 1399be8a82cSStrahinja Jankovic case TWI_DATA_REG: 1409be8a82cSStrahinja Jankovic return "DATA"; 1419be8a82cSStrahinja Jankovic case TWI_CNTR_REG: 1429be8a82cSStrahinja Jankovic return "CNTR"; 1439be8a82cSStrahinja Jankovic case TWI_STAT_REG: 1449be8a82cSStrahinja Jankovic return "STAT"; 1459be8a82cSStrahinja Jankovic case TWI_CCR_REG: 1469be8a82cSStrahinja Jankovic return "CCR"; 1479be8a82cSStrahinja Jankovic case TWI_SRST_REG: 1489be8a82cSStrahinja Jankovic return "SRST"; 1499be8a82cSStrahinja Jankovic case TWI_EFR_REG: 1509be8a82cSStrahinja Jankovic return "EFR"; 1519be8a82cSStrahinja Jankovic case TWI_LCR_REG: 1529be8a82cSStrahinja Jankovic return "LCR"; 1539be8a82cSStrahinja Jankovic default: 1549be8a82cSStrahinja Jankovic return "[?]"; 1559be8a82cSStrahinja Jankovic } 1569be8a82cSStrahinja Jankovic } 1579be8a82cSStrahinja Jankovic 1589be8a82cSStrahinja Jankovic static inline bool allwinner_i2c_is_reset(AWI2CState *s) 1599be8a82cSStrahinja Jankovic { 1609be8a82cSStrahinja Jankovic return s->srst & TWI_SRST_MASK; 1619be8a82cSStrahinja Jankovic } 1629be8a82cSStrahinja Jankovic 1639be8a82cSStrahinja Jankovic static inline bool allwinner_i2c_bus_is_enabled(AWI2CState *s) 1649be8a82cSStrahinja Jankovic { 1659be8a82cSStrahinja Jankovic return s->cntr & TWI_CNTR_BUS_EN; 1669be8a82cSStrahinja Jankovic } 1679be8a82cSStrahinja Jankovic 1689be8a82cSStrahinja Jankovic static inline bool allwinner_i2c_interrupt_is_enabled(AWI2CState *s) 1699be8a82cSStrahinja Jankovic { 1709be8a82cSStrahinja Jankovic return s->cntr & TWI_CNTR_INT_EN; 1719be8a82cSStrahinja Jankovic } 1729be8a82cSStrahinja Jankovic 173*ad80e367SPeter Maydell static void allwinner_i2c_reset_hold(Object *obj, ResetType type) 1749be8a82cSStrahinja Jankovic { 1759be8a82cSStrahinja Jankovic AWI2CState *s = AW_I2C(obj); 1769be8a82cSStrahinja Jankovic 1779be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) != STAT_IDLE) { 1789be8a82cSStrahinja Jankovic i2c_end_transfer(s->bus); 1799be8a82cSStrahinja Jankovic } 1809be8a82cSStrahinja Jankovic 1819be8a82cSStrahinja Jankovic s->addr = TWI_ADDR_RESET; 1829be8a82cSStrahinja Jankovic s->xaddr = TWI_XADDR_RESET; 1839be8a82cSStrahinja Jankovic s->data = TWI_DATA_RESET; 1849be8a82cSStrahinja Jankovic s->cntr = TWI_CNTR_RESET; 1859be8a82cSStrahinja Jankovic s->stat = TWI_STAT_RESET; 1869be8a82cSStrahinja Jankovic s->ccr = TWI_CCR_RESET; 1879be8a82cSStrahinja Jankovic s->srst = TWI_SRST_RESET; 1889be8a82cSStrahinja Jankovic s->efr = TWI_EFR_RESET; 1899be8a82cSStrahinja Jankovic s->lcr = TWI_LCR_RESET; 1909be8a82cSStrahinja Jankovic } 1919be8a82cSStrahinja Jankovic 1929be8a82cSStrahinja Jankovic static inline void allwinner_i2c_raise_interrupt(AWI2CState *s) 1939be8a82cSStrahinja Jankovic { 1949be8a82cSStrahinja Jankovic /* 1959be8a82cSStrahinja Jankovic * Raise an interrupt if the device is not reset and it is configured 1969be8a82cSStrahinja Jankovic * to generate some interrupts. 1979be8a82cSStrahinja Jankovic */ 1989be8a82cSStrahinja Jankovic if (!allwinner_i2c_is_reset(s) && allwinner_i2c_bus_is_enabled(s)) { 1999be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) != STAT_IDLE) { 2009be8a82cSStrahinja Jankovic s->cntr |= TWI_CNTR_INT_FLAG; 2019be8a82cSStrahinja Jankovic if (allwinner_i2c_interrupt_is_enabled(s)) { 2029be8a82cSStrahinja Jankovic qemu_irq_raise(s->irq); 2039be8a82cSStrahinja Jankovic } 2049be8a82cSStrahinja Jankovic } 2059be8a82cSStrahinja Jankovic } 2069be8a82cSStrahinja Jankovic } 2079be8a82cSStrahinja Jankovic 2089be8a82cSStrahinja Jankovic static uint64_t allwinner_i2c_read(void *opaque, hwaddr offset, 2099be8a82cSStrahinja Jankovic unsigned size) 2109be8a82cSStrahinja Jankovic { 2119be8a82cSStrahinja Jankovic uint16_t value; 2129be8a82cSStrahinja Jankovic AWI2CState *s = AW_I2C(opaque); 2139be8a82cSStrahinja Jankovic 2149be8a82cSStrahinja Jankovic switch (offset) { 2159be8a82cSStrahinja Jankovic case TWI_ADDR_REG: 2169be8a82cSStrahinja Jankovic value = s->addr; 2179be8a82cSStrahinja Jankovic break; 2189be8a82cSStrahinja Jankovic case TWI_XADDR_REG: 2199be8a82cSStrahinja Jankovic value = s->xaddr; 2209be8a82cSStrahinja Jankovic break; 2219be8a82cSStrahinja Jankovic case TWI_DATA_REG: 2229be8a82cSStrahinja Jankovic if ((STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) || 2239be8a82cSStrahinja Jankovic (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) || 2249be8a82cSStrahinja Jankovic (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK)) { 2259be8a82cSStrahinja Jankovic /* Get the next byte */ 2269be8a82cSStrahinja Jankovic s->data = i2c_recv(s->bus); 2279be8a82cSStrahinja Jankovic 2289be8a82cSStrahinja Jankovic if (s->cntr & TWI_CNTR_A_ACK) { 2299be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); 2309be8a82cSStrahinja Jankovic } else { 2319be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); 2329be8a82cSStrahinja Jankovic } 2339be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s); 2349be8a82cSStrahinja Jankovic } 2359be8a82cSStrahinja Jankovic value = s->data; 2369be8a82cSStrahinja Jankovic break; 2379be8a82cSStrahinja Jankovic case TWI_CNTR_REG: 2389be8a82cSStrahinja Jankovic value = s->cntr; 2399be8a82cSStrahinja Jankovic break; 2409be8a82cSStrahinja Jankovic case TWI_STAT_REG: 2419be8a82cSStrahinja Jankovic value = s->stat; 2429be8a82cSStrahinja Jankovic /* 2439be8a82cSStrahinja Jankovic * If polling when reading then change state to indicate data 2449be8a82cSStrahinja Jankovic * is available 2459be8a82cSStrahinja Jankovic */ 2469be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) { 2479be8a82cSStrahinja Jankovic if (s->cntr & TWI_CNTR_A_ACK) { 2489be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); 2499be8a82cSStrahinja Jankovic } else { 2509be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); 2519be8a82cSStrahinja Jankovic } 2529be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s); 2539be8a82cSStrahinja Jankovic } 2549be8a82cSStrahinja Jankovic break; 2559be8a82cSStrahinja Jankovic case TWI_CCR_REG: 2569be8a82cSStrahinja Jankovic value = s->ccr; 2579be8a82cSStrahinja Jankovic break; 2589be8a82cSStrahinja Jankovic case TWI_SRST_REG: 2599be8a82cSStrahinja Jankovic value = s->srst; 2609be8a82cSStrahinja Jankovic break; 2619be8a82cSStrahinja Jankovic case TWI_EFR_REG: 2629be8a82cSStrahinja Jankovic value = s->efr; 2639be8a82cSStrahinja Jankovic break; 2649be8a82cSStrahinja Jankovic case TWI_LCR_REG: 2659be8a82cSStrahinja Jankovic value = s->lcr; 2669be8a82cSStrahinja Jankovic break; 2679be8a82cSStrahinja Jankovic default: 2689be8a82cSStrahinja Jankovic qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" 2699be8a82cSStrahinja Jankovic HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset); 2709be8a82cSStrahinja Jankovic value = 0; 2719be8a82cSStrahinja Jankovic break; 2729be8a82cSStrahinja Jankovic } 2739be8a82cSStrahinja Jankovic 2749be8a82cSStrahinja Jankovic trace_allwinner_i2c_read(allwinner_i2c_get_regname(offset), offset, value); 2759be8a82cSStrahinja Jankovic 2769be8a82cSStrahinja Jankovic return (uint64_t)value; 2779be8a82cSStrahinja Jankovic } 2789be8a82cSStrahinja Jankovic 2799be8a82cSStrahinja Jankovic static void allwinner_i2c_write(void *opaque, hwaddr offset, 2809be8a82cSStrahinja Jankovic uint64_t value, unsigned size) 2819be8a82cSStrahinja Jankovic { 2829be8a82cSStrahinja Jankovic AWI2CState *s = AW_I2C(opaque); 2839be8a82cSStrahinja Jankovic 2849be8a82cSStrahinja Jankovic value &= 0xff; 2859be8a82cSStrahinja Jankovic 2869be8a82cSStrahinja Jankovic trace_allwinner_i2c_write(allwinner_i2c_get_regname(offset), offset, value); 2879be8a82cSStrahinja Jankovic 2889be8a82cSStrahinja Jankovic switch (offset) { 2899be8a82cSStrahinja Jankovic case TWI_ADDR_REG: 2909be8a82cSStrahinja Jankovic s->addr = (uint8_t)value; 2919be8a82cSStrahinja Jankovic break; 2929be8a82cSStrahinja Jankovic case TWI_XADDR_REG: 2939be8a82cSStrahinja Jankovic s->xaddr = (uint8_t)value; 2949be8a82cSStrahinja Jankovic break; 2959be8a82cSStrahinja Jankovic case TWI_DATA_REG: 2969be8a82cSStrahinja Jankovic /* If the device is in reset or not enabled, nothing to do */ 2979be8a82cSStrahinja Jankovic if (allwinner_i2c_is_reset(s) || (!allwinner_i2c_bus_is_enabled(s))) { 2989be8a82cSStrahinja Jankovic break; 2999be8a82cSStrahinja Jankovic } 3009be8a82cSStrahinja Jankovic 3019be8a82cSStrahinja Jankovic s->data = value & TWI_DATA_MASK; 3029be8a82cSStrahinja Jankovic 3039be8a82cSStrahinja Jankovic switch (STAT_TO_STA(s->stat)) { 3049be8a82cSStrahinja Jankovic case STAT_M_STA_TX: 3059be8a82cSStrahinja Jankovic case STAT_M_RSTA_TX: 3069be8a82cSStrahinja Jankovic /* Send address */ 3079be8a82cSStrahinja Jankovic if (i2c_start_transfer(s->bus, extract32(s->data, 1, 7), 3089be8a82cSStrahinja Jankovic extract32(s->data, 0, 1))) { 3099be8a82cSStrahinja Jankovic /* If non zero is returned, the address is not valid */ 3109be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_NACK); 3119be8a82cSStrahinja Jankovic } else { 3129be8a82cSStrahinja Jankovic /* Determine if read of write */ 3139be8a82cSStrahinja Jankovic if (extract32(s->data, 0, 1)) { 3149be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_ADDR_RD_ACK); 3159be8a82cSStrahinja Jankovic } else { 3169be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_ACK); 3179be8a82cSStrahinja Jankovic } 3189be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s); 3199be8a82cSStrahinja Jankovic } 3209be8a82cSStrahinja Jankovic break; 3219be8a82cSStrahinja Jankovic case STAT_M_ADDR_WR_ACK: 3229be8a82cSStrahinja Jankovic case STAT_M_DATA_TX_ACK: 3239be8a82cSStrahinja Jankovic if (i2c_send(s->bus, s->data)) { 3249be8a82cSStrahinja Jankovic /* If the target return non zero then end the transfer */ 3259be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_TX_NACK); 3269be8a82cSStrahinja Jankovic i2c_end_transfer(s->bus); 3279be8a82cSStrahinja Jankovic } else { 3289be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_TX_ACK); 3299be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s); 3309be8a82cSStrahinja Jankovic } 3319be8a82cSStrahinja Jankovic break; 3329be8a82cSStrahinja Jankovic default: 3339be8a82cSStrahinja Jankovic break; 3349be8a82cSStrahinja Jankovic } 3359be8a82cSStrahinja Jankovic break; 3369be8a82cSStrahinja Jankovic case TWI_CNTR_REG: 3379be8a82cSStrahinja Jankovic if (!allwinner_i2c_is_reset(s)) { 3389be8a82cSStrahinja Jankovic /* Do something only if not in software reset */ 3399be8a82cSStrahinja Jankovic s->cntr = value & TWI_CNTR_MASK; 3409be8a82cSStrahinja Jankovic 3419be8a82cSStrahinja Jankovic /* Check if start condition should be sent */ 3429be8a82cSStrahinja Jankovic if (s->cntr & TWI_CNTR_M_STA) { 3439be8a82cSStrahinja Jankovic /* Update status */ 3449be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) == STAT_IDLE) { 3459be8a82cSStrahinja Jankovic /* Send start condition */ 3469be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_STA_TX); 3479be8a82cSStrahinja Jankovic } else { 3489be8a82cSStrahinja Jankovic /* Send repeated start condition */ 3499be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_RSTA_TX); 3509be8a82cSStrahinja Jankovic } 3519be8a82cSStrahinja Jankovic /* Clear start condition */ 3529be8a82cSStrahinja Jankovic s->cntr &= ~TWI_CNTR_M_STA; 3539be8a82cSStrahinja Jankovic } 3549be8a82cSStrahinja Jankovic if (s->cntr & TWI_CNTR_M_STP) { 3559be8a82cSStrahinja Jankovic /* Update status */ 3569be8a82cSStrahinja Jankovic i2c_end_transfer(s->bus); 3579be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_IDLE); 3589be8a82cSStrahinja Jankovic s->cntr &= ~TWI_CNTR_M_STP; 3599be8a82cSStrahinja Jankovic } 3608461bfdcSqianfan Zhao 3618461bfdcSqianfan Zhao if (!s->irq_clear_inverted && !(s->cntr & TWI_CNTR_INT_FLAG)) { 3628461bfdcSqianfan Zhao /* Write 0 to clear this flag */ 3638461bfdcSqianfan Zhao qemu_irq_lower(s->irq); 3648461bfdcSqianfan Zhao } else if (s->irq_clear_inverted && (s->cntr & TWI_CNTR_INT_FLAG)) { 3658461bfdcSqianfan Zhao /* Write 1 to clear this flag */ 3668461bfdcSqianfan Zhao s->cntr &= ~TWI_CNTR_INT_FLAG; 3679be8a82cSStrahinja Jankovic qemu_irq_lower(s->irq); 3689be8a82cSStrahinja Jankovic } 3698461bfdcSqianfan Zhao 3709be8a82cSStrahinja Jankovic if ((s->cntr & TWI_CNTR_A_ACK) == 0) { 3719be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) { 3729be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); 3739be8a82cSStrahinja Jankovic } 3749be8a82cSStrahinja Jankovic } else { 3759be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK) { 3769be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); 3779be8a82cSStrahinja Jankovic } 3789be8a82cSStrahinja Jankovic } 3799be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s); 3809be8a82cSStrahinja Jankovic 3819be8a82cSStrahinja Jankovic } 3829be8a82cSStrahinja Jankovic break; 3839be8a82cSStrahinja Jankovic case TWI_CCR_REG: 3849be8a82cSStrahinja Jankovic s->ccr = value & TWI_CCR_MASK; 3859be8a82cSStrahinja Jankovic break; 3869be8a82cSStrahinja Jankovic case TWI_SRST_REG: 3879be8a82cSStrahinja Jankovic if (((value & TWI_SRST_MASK) == 0) && (s->srst & TWI_SRST_MASK)) { 388ef6ab292SPeter Maydell device_cold_reset(DEVICE(s)); 3899be8a82cSStrahinja Jankovic } 3909be8a82cSStrahinja Jankovic s->srst = value & TWI_SRST_MASK; 3919be8a82cSStrahinja Jankovic break; 3929be8a82cSStrahinja Jankovic case TWI_EFR_REG: 3939be8a82cSStrahinja Jankovic s->efr = value & TWI_EFR_MASK; 3949be8a82cSStrahinja Jankovic break; 3959be8a82cSStrahinja Jankovic case TWI_LCR_REG: 3969be8a82cSStrahinja Jankovic s->lcr = value & TWI_LCR_MASK; 3979be8a82cSStrahinja Jankovic break; 3989be8a82cSStrahinja Jankovic default: 3999be8a82cSStrahinja Jankovic qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" 4009be8a82cSStrahinja Jankovic HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset); 4019be8a82cSStrahinja Jankovic break; 4029be8a82cSStrahinja Jankovic } 4039be8a82cSStrahinja Jankovic } 4049be8a82cSStrahinja Jankovic 4059be8a82cSStrahinja Jankovic static const MemoryRegionOps allwinner_i2c_ops = { 4069be8a82cSStrahinja Jankovic .read = allwinner_i2c_read, 4079be8a82cSStrahinja Jankovic .write = allwinner_i2c_write, 4089be8a82cSStrahinja Jankovic .valid.min_access_size = 1, 4099be8a82cSStrahinja Jankovic .valid.max_access_size = 4, 4109be8a82cSStrahinja Jankovic .endianness = DEVICE_NATIVE_ENDIAN, 4119be8a82cSStrahinja Jankovic }; 4129be8a82cSStrahinja Jankovic 4139be8a82cSStrahinja Jankovic static const VMStateDescription allwinner_i2c_vmstate = { 4149be8a82cSStrahinja Jankovic .name = TYPE_AW_I2C, 4159be8a82cSStrahinja Jankovic .version_id = 1, 4169be8a82cSStrahinja Jankovic .minimum_version_id = 1, 41701d9442aSRichard Henderson .fields = (const VMStateField[]) { 4189be8a82cSStrahinja Jankovic VMSTATE_UINT8(addr, AWI2CState), 4199be8a82cSStrahinja Jankovic VMSTATE_UINT8(xaddr, AWI2CState), 4209be8a82cSStrahinja Jankovic VMSTATE_UINT8(data, AWI2CState), 4219be8a82cSStrahinja Jankovic VMSTATE_UINT8(cntr, AWI2CState), 4229be8a82cSStrahinja Jankovic VMSTATE_UINT8(ccr, AWI2CState), 4239be8a82cSStrahinja Jankovic VMSTATE_UINT8(srst, AWI2CState), 4249be8a82cSStrahinja Jankovic VMSTATE_UINT8(efr, AWI2CState), 4259be8a82cSStrahinja Jankovic VMSTATE_UINT8(lcr, AWI2CState), 4269be8a82cSStrahinja Jankovic VMSTATE_END_OF_LIST() 4279be8a82cSStrahinja Jankovic } 4289be8a82cSStrahinja Jankovic }; 4299be8a82cSStrahinja Jankovic 4309be8a82cSStrahinja Jankovic static void allwinner_i2c_realize(DeviceState *dev, Error **errp) 4319be8a82cSStrahinja Jankovic { 4329be8a82cSStrahinja Jankovic AWI2CState *s = AW_I2C(dev); 4339be8a82cSStrahinja Jankovic 4349be8a82cSStrahinja Jankovic memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_i2c_ops, s, 4359be8a82cSStrahinja Jankovic TYPE_AW_I2C, AW_I2C_MEM_SIZE); 4369be8a82cSStrahinja Jankovic sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); 4379be8a82cSStrahinja Jankovic sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 4389be8a82cSStrahinja Jankovic s->bus = i2c_init_bus(dev, "i2c"); 4399be8a82cSStrahinja Jankovic } 4409be8a82cSStrahinja Jankovic 4419be8a82cSStrahinja Jankovic static void allwinner_i2c_class_init(ObjectClass *klass, void *data) 4429be8a82cSStrahinja Jankovic { 4439be8a82cSStrahinja Jankovic DeviceClass *dc = DEVICE_CLASS(klass); 4449be8a82cSStrahinja Jankovic ResettableClass *rc = RESETTABLE_CLASS(klass); 4459be8a82cSStrahinja Jankovic 4469be8a82cSStrahinja Jankovic rc->phases.hold = allwinner_i2c_reset_hold; 4479be8a82cSStrahinja Jankovic dc->vmsd = &allwinner_i2c_vmstate; 4489be8a82cSStrahinja Jankovic dc->realize = allwinner_i2c_realize; 4499be8a82cSStrahinja Jankovic dc->desc = "Allwinner I2C Controller"; 4509be8a82cSStrahinja Jankovic } 4519be8a82cSStrahinja Jankovic 4529be8a82cSStrahinja Jankovic static const TypeInfo allwinner_i2c_type_info = { 4539be8a82cSStrahinja Jankovic .name = TYPE_AW_I2C, 4549be8a82cSStrahinja Jankovic .parent = TYPE_SYS_BUS_DEVICE, 4559be8a82cSStrahinja Jankovic .instance_size = sizeof(AWI2CState), 4569be8a82cSStrahinja Jankovic .class_init = allwinner_i2c_class_init, 4579be8a82cSStrahinja Jankovic }; 4589be8a82cSStrahinja Jankovic 4598461bfdcSqianfan Zhao static void allwinner_i2c_sun6i_init(Object *obj) 4608461bfdcSqianfan Zhao { 4618461bfdcSqianfan Zhao AWI2CState *s = AW_I2C(obj); 4628461bfdcSqianfan Zhao 4638461bfdcSqianfan Zhao s->irq_clear_inverted = true; 4648461bfdcSqianfan Zhao } 4658461bfdcSqianfan Zhao 4668461bfdcSqianfan Zhao static const TypeInfo allwinner_i2c_sun6i_type_info = { 4678461bfdcSqianfan Zhao .name = TYPE_AW_I2C_SUN6I, 4686c50845aSPeter Maydell .parent = TYPE_AW_I2C, 4698461bfdcSqianfan Zhao .instance_init = allwinner_i2c_sun6i_init, 4708461bfdcSqianfan Zhao }; 4718461bfdcSqianfan Zhao 4729be8a82cSStrahinja Jankovic static void allwinner_i2c_register_types(void) 4739be8a82cSStrahinja Jankovic { 4749be8a82cSStrahinja Jankovic type_register_static(&allwinner_i2c_type_info); 4758461bfdcSqianfan Zhao type_register_static(&allwinner_i2c_sun6i_type_info); 4769be8a82cSStrahinja Jankovic } 4779be8a82cSStrahinja Jankovic 4789be8a82cSStrahinja Jankovic type_init(allwinner_i2c_register_types) 479