// SPDX-License-Identifier: GPL-2.0
/*
* Xilinx Versal memory controller driver
* Copyright (C) 2023 Advanced Micro Devices, Inc.
*/
#include <linux/bitfield.h>
#include <linux/edac.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/sizes.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include <linux/firmware/xlnx-event-manager.h>
#include "edac_module.h"
/* Granularity of reported error in bytes */
#define XDDR_EDAC_ERR_GRAIN 1
#define XDDR_EDAC_MSG_SIZE 256
#define EVENT 2
#define XDDR_PCSR_OFFSET 0xC
#define XDDR_ISR_OFFSET 0x14
#define XDDR_IRQ_EN_OFFSET 0x20
#define XDDR_IRQ1_EN_OFFSET 0x2C
#define XDDR_IRQ_DIS_OFFSET 0x24
#define XDDR_IRQ_CE_MASK GENMASK(18, 15)
#define XDDR_IRQ_UE_MASK GENMASK(14, 11)
#define XDDR_REG_CONFIG0_OFFSET 0x258
#define XDDR_REG_CONFIG0_BUS_WIDTH_MASK GENMASK(19, 18)
#define XDDR_REG_CONFIG0_NUM_CHANS_MASK BIT(17)
#define XDDR_REG_CONFIG0_NUM_RANKS_MASK GENMASK(15, 14)
#define XDDR_REG_CONFIG0_SIZE_MASK GENMASK(10, 8)
#define XDDR_REG_PINOUT_OFFSET 0x25C
#define XDDR_REG_PINOUT_ECC_EN_MASK GENMASK(7, 5)
#define ECCW0_FLIP_CTRL 0x109C
#define ECCW0_FLIP0_OFFSET 0x10A0
#define ECCW0_FLIP0_BITS 31
#define ECCW0_FLIP1_OFFSET 0x10A4
#define ECCW1_FLIP_CTRL 0x10AC
#define ECCW1_FLIP0_OFFSET 0x10B0
#define ECCW1_FLIP1_OFFSET 0x10B4
#define ECCR0_CERR_STAT_OFFSET 0x10BC
#define ECCR0_CE_ADDR_LO_OFFSET 0x10C0
#define ECCR0_CE_ADDR_HI_OFFSET 0x10C4
#define ECCR0_CE_DATA_LO_OFFSET 0x10C8
#define ECCR0_CE_DATA_HI_OFFSET 0x10CC
#define ECCR0_CE_DATA_PAR_OFFSET 0x10D0
#define ECCR0_UERR_STAT_OFFSET 0x10D4
#define ECCR0_UE_ADDR_LO_OFFSET 0x10D8
#define ECCR0_UE_ADDR_HI_OFFSET 0x10DC
#define ECCR0_UE_DATA_LO_OFFSET 0x10E0
#define ECCR0_UE_DATA_HI_OFFSET 0x10E4
#define ECCR0_UE_DATA_PAR_OFFSET 0x10E8
#define ECCR1_CERR_STAT_OFFSET 0x10F4
#define ECCR1_CE_ADDR_LO_OFFSET 0x10F8
#define ECCR1_CE_ADDR_HI_OFFSET 0x10FC
#define ECCR1_CE_DATA_LO_OFFSET 0x1100
#define ECCR1_CE_DATA_HI_OFFSET 0x110C
#define ECCR1_CE_DATA_PAR_OFFSET 0x1108
#define ECCR1_UERR_STAT_OFFSET 0x110C
#define ECCR1_UE_ADDR_LO_OFFSET 0x1110
#define ECCR1_UE_ADDR_HI_OFFSET 0x1114
#define ECCR1_UE_DATA_LO_OFFSET 0x1118
#define ECCR1_UE_DATA_HI_OFFSET 0x111C
#define ECCR1_UE_DATA_PAR_OFFSET 0x1120
#define XDDR_NOC_REG_ADEC4_OFFSET 0x44
#define RANK_1_MASK GENMASK(11, 6)
#define LRANK_0_MASK GENMASK(17, 12)
#define LRANK_1_MASK GENMASK(23, 18)
#define MASK_24 GENMASK(29, 24)
#define XDDR_NOC_REG_ADEC5_OFFSET 0x48
#define XDDR_NOC_REG_ADEC6_OFFSET 0x4C
#define XDDR_NOC_REG_ADEC7_OFFSET 0x50
#define XDDR_NOC_REG_ADEC8_OFFSET 0x54
#define XDDR_NOC_REG_ADEC9_OFFSET 0x58
#define XDDR_NOC_REG_ADEC10_OFFSET 0x5C
#define XDDR_NOC_REG_ADEC11_OFFSET 0x60
#define MASK_0 GENMASK(5, 0)
#define GRP_0_MASK GENMASK(11, 6)
#define GRP_1_MASK GENMASK(17, 12)
#define CH_0_MASK GENMASK(23, 18)
#define XDDR_NOC_REG_ADEC12_OFFSET 0x71C
#define XDDR_NOC_REG_ADEC13_OFFSET 0x720
#define XDDR_NOC_REG_ADEC14_OFFSET 0x724
#define XDDR_NOC_ROW_MATCH_MASK GENMASK(17, 0)
#define XDDR_NOC_COL_MATCH_MASK GENMASK(27, 18)
#define XDDR_NOC_BANK_MATCH_MASK GENMASK(29, 28)
#define XDDR_NOC_GRP_MATCH_MASK GENMASK(31, 30)
#define XDDR_NOC_REG_ADEC15_OFFSET 0x728
#define XDDR_NOC_RANK_MATCH_MASK GENMASK(1, 0)
#define XDDR_NOC_LRANK_MATCH_MASK GENMASK(4, 2)
#define XDDR_NOC_CH_MATCH_MASK BIT(5)
#define XDDR_NOC_MOD_SEL_MASK BIT(6)
#define XDDR_NOC_MATCH_EN_MASK BIT(8)
#define ECCR_UE_CE_ADDR_HI_ROW_MASK GENMASK(7, 0)
#define XDDR_EDAC_NR_CSROWS 1
#define XDDR_EDAC_NR_CHANS 1
#define XDDR_BUS_WIDTH_64 0
#define XDDR_BUS_WIDTH_32 1
#define XDDR_BUS_WIDTH_16 2
#define XDDR_MAX_ROW_CNT 18
#define XDDR_MAX_COL_CNT 10
#define XDDR_MAX_RANK_CNT 2
#define XDDR_MAX_LRANK_CNT 3
#define XDDR_MAX_BANK_CNT 2
#define XDDR_MAX_GRP_CNT 2
/*
* Config and system registers are usually locked. This is the
* code which unlocks them in order to accept writes. See
*
* https://docs.xilinx.com/r/en-US/am012-versal-register-reference/PCSR_LOCK-XRAM_SLCR-Register
*/
#define PCSR_UNLOCK_VAL 0xF9E8D7C6
#define PCSR_LOCK_VAL 1
#define XDDR_ERR_TYPE_CE 0
#define XDDR_ERR_TYPE_UE 1
#define XILINX_DRAM_SIZE_4G 0
#define XILINX_DRAM_SIZE_6G 1
#define XILINX_DRAM_SIZE_8G 2
#define XILINX_DRAM_SIZE_12G 3
#define XILINX_DRAM_SIZE_16G 4
#define XILINX_DRAM_SIZE_32G 5
#define NUM_UE_BITPOS 2
/**
* struct ecc_error_info - ECC error log information.
* @burstpos: Burst position.
* @lrank: Logical Rank number.
* @rank: Rank number.
* @group: Group number.
* @bank: Bank number.
* @col: Column number.
* @row: Row number.
* @rowhi: Row number higher bits.
* @i: ECC error info.
*/
union ecc_error_info {
struct {
u32 burstpos:3;
u32 lrank:3;
u32 rank:2;
u32 group:2;
u32 bank:2;
u32 col:10;
u32 row:10;
u32 rowhi;
};
u64 i;
} __packed;
union edac_info {
struct {
u32 row0:6;
u32 row1:6;
u32 row2:6;
u32 row3:6;
u32 row4:6;
u32 reserved:2;
};
struct {
u32 col1:6;
u32 col2:6;
u32 col3:6;
u32 col4:6;
u32 col5:6;
u32 reservedcol:2;
};
u32 i;
} __packed;
/**
* struct ecc_status - ECC status information to report.
* @ceinfo: Correctable error log information.
* @ueinfo: Uncorrectable error log information.
* @channel: Channel number.
* @error_type: Error type information.
*/
struct ecc_status {
union ecc_error_info ceinfo[2];
union ecc_error_info ueinfo[2];
u8 channel;
u8 error_type;
};
/**
* struct edac_priv - DDR memory controller private instance data.
* @ddrmc_baseaddr: Base address of the DDR controller.
* @ddrmc_noc_baseaddr: Base address of the DDRMC NOC.
* @message: Buffer for framing the eve