// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics 2020
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <linux/reset.h>
/* FMC2 Controller Registers */
#define FMC2_BCR1 0x0
#define FMC2_BTR1 0x4
#define FMC2_BCR(x) ((x) * 0x8 + FMC2_BCR1)
#define FMC2_BTR(x) ((x) * 0x8 + FMC2_BTR1)
#define FMC2_PCSCNTR 0x20
#define FMC2_BWTR1 0x104
#define FMC2_BWTR(x) ((x) * 0x8 + FMC2_BWTR1)
/* Register: FMC2_BCR1 */
#define FMC2_BCR1_CCLKEN BIT(20)
#define FMC2_BCR1_FMC2EN BIT(31)
/* Register: FMC2_BCRx */
#define FMC2_BCR_MBKEN BIT(0)
#define FMC2_BCR_MUXEN BIT(1)
#define FMC2_BCR_MTYP GENMASK(3, 2)
#define FMC2_BCR_MWID GENMASK(5, 4)
#define FMC2_BCR_FACCEN BIT(6)
#define FMC2_BCR_BURSTEN BIT(8)
#define FMC2_BCR_WAITPOL BIT(9)
#define FMC2_BCR_WAITCFG BIT(11)
#define FMC2_BCR_WREN BIT(12)
#define FMC2_BCR_WAITEN BIT(13)
#define FMC2_BCR_EXTMOD BIT(14)
#define FMC2_BCR_ASYNCWAIT BIT(15)
#define FMC2_BCR_CPSIZE GENMASK(18, 16)
#define FMC2_BCR_CBURSTRW BIT(19)
#define FMC2_BCR_NBLSET GENMASK(23, 22)
/* Register: FMC2_BTRx/FMC2_BWTRx */
#define FMC2_BXTR_ADDSET GENMASK(3, 0)
#define FMC2_BXTR_ADDHLD GENMASK(7, 4)
#define FMC2_BXTR_DATAST GENMASK(15, 8)
#define FMC2_BXTR_BUSTURN GENMASK(19, 16)
#define FMC2_BTR_CLKDIV GENMASK(23, 20)
#define FMC2_BTR_DATLAT GENMASK(27, 24)
#define FMC2_BXTR_ACCMOD GENMASK(29, 28)
#define FMC2_BXTR_DATAHLD GENMASK(31, 30)
/* Register: FMC2_PCSCNTR */
#define FMC2_PCSCNTR_CSCOUNT GENMASK(15, 0)
#define FMC2_PCSCNTR_CNTBEN(x) BIT((x) + 16)
#define FMC2_MAX_EBI_CE 4
#define FMC2_MAX_BANKS 5
#define FMC2_BCR_CPSIZE_0 0x0
#define FMC2_BCR_CPSIZE_128 0x1
#define FMC2_BCR_CPSIZE_256 0x2
#define FMC2_BCR_CPSIZE_512 0x3
#define FMC2_BCR_CPSIZE_1024 0x4
#define FMC2_BCR_MWID_8 0x0
#define FMC2_BCR_MWID_16 0x1
#define FMC2_BCR_MTYP_SRAM 0x0
#define FMC2_BCR_MTYP_PSRAM 0x1
#define FMC2_BCR_MTYP_NOR 0x2
#define FMC2_BXTR_EXTMOD_A 0x0
#define FMC2_BXTR_EXTMOD_B 0x1
#define FMC2_BXTR_EXTMOD_C 0x2
#define FMC2_BXTR_EXTMOD_D 0x3
#define FMC2_BCR_NBLSET_MAX 0x3
#define FMC2_BXTR_ADDSET_MAX 0xf
#define FMC2_BXTR_ADDHLD_MAX 0xf
#define FMC2_BXTR_DATAST_MAX 0xff
#define FMC2_BXTR_BUSTURN_MAX 0xf
#define FMC2_BXTR_DATAHLD_MAX 0x3
#define FMC2_BTR_CLKDIV_MAX 0xf
#define FMC2_BTR_DATLAT_MAX 0xf
#define FMC2_PCSCNTR_CSCOUNT_MAX 0xff
enum stm32_fmc2_ebi_bank {
FMC2_EBI1 = 0,
FMC2_EBI2,
FMC2_EBI3,
FMC2_EBI4,
FMC2_NAND
};
enum stm32_fmc2_ebi_register_type {
FMC2_REG_BCR = 1,
FMC2_REG_BTR,
FMC2_REG_BWTR,
FMC2_REG_PCSCNTR
};
enum stm32_fmc2_ebi_transaction_type {
FMC2_ASYNC_MODE_1_SRAM = 0,
FMC2_ASYNC_MODE_1_PSRAM,
FMC2_ASYNC_MODE_A_SRAM,
FMC2_ASYNC_MODE_A_PSRAM,
FMC2_ASYNC_MODE_2_NOR,
FMC2_ASYNC_MODE_B_NOR,
FMC2_ASYNC_MODE_C_NOR,
FMC2_ASYNC_MODE_D_NOR,
FMC2_SYNC_READ_SYNC_WRITE_PSRAM,
FMC2_SYNC_READ_ASYNC_WRITE_PSRAM,
FMC2_SYNC_READ_SYNC_WRITE_NOR,
FMC2_SYNC_READ_ASYNC_WRITE_NOR
};
enum stm32_fmc2_ebi_buswidth {
FMC2_BUSWIDTH_8 = 8,
FMC2_BUSWIDTH_16 = 16
};
enum stm32_fmc2_ebi_cpsize {
FMC2_CPSIZE_0 = 0,
FMC2_CPSIZE_128 = 128,
FMC2_CPSIZE_256 = 256,
FMC2_CPSIZE_512 = 512,
FMC2_CPSIZE_1024 = 1024
};
struct stm32_fmc2_ebi {
struct device *dev;
struct clk *clk;
struct regmap *regmap;
u8 bank_assigned;
u32 bcr[FMC2_MAX_EBI_CE];
u32 btr[FMC2_MAX_EBI_CE];
u32 bwtr[FMC2_MAX_EBI_CE];
u32 pcscntr;
};
/*
* struct stm32_fmc2_prop - STM32 FMC2 EBI property
* @name: the device tree binding name of the property
* @bprop: indicate that it is a boolean property
* @mprop: indicate that it is a mandatory property
* @reg_type: the register that have to be modified
* @reg_mask: the bit that have to be modified in the selected register
* in case of it is a boolean property
* @reset_val: the default value that have to be set in case the property
* has not been defined in the device tree
* @check: this callback ckecks that the property is compliant with the
* transaction type selected
* @calculate: this callback is called to calculate for exemple a timing
* set in nanoseconds in the device tree in clock cycles or in
* clock period
* @set: this callback applies the values in the registers
*/
struct stm32_fmc2_prop {
const char *name;
bool bprop;
bool mprop;
int reg_type;
u32 reg_mask;
u32 reset_val;
int (*check)(struct stm32_fmc2_ebi *ebi,
const struct stm32_fmc2_prop *prop, int cs);
u32 (*calculate)(struct stm32_fmc2_ebi *ebi, int cs, u32 setup);
int (*set)(struct stm32_fmc2_ebi *ebi,
const struct stm32_fmc2_prop *prop,
int cs, u32 setup);
};
static int stm32_fmc2_ebi_check_mux(struct stm32_fmc2_ebi *ebi,
const struct stm32_fmc2_prop *prop,
int cs)
{
u32 bcr;
regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
if (bcr & FMC2_BCR_MTYP)
return 0;
return -EINVAL;
}
static int stm32_fmc2_ebi_check_waitcfg(struct stm32_fmc2_ebi *ebi,
const struct stm32_fmc2_prop *prop,
int cs)
{
u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR);
regmap_read(ebi->r