linux/drivers/memory/omap-gpmc.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * GPMC support functions
 *
 * Copyright (C) 2005-2006 Nokia Corporation
 *
 * Author: Juha Yrjola
 *
 * Copyright (C) 2009 Texas Instruments
 * Added OMAP4 support - Santosh Shilimkar <[email protected]>
 */
#include <linux/cpu_pm.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h> /* GPIO descriptor enum */
#include <linux/gpio/machine.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/omap-gpmc.h>
#include <linux/pm_runtime.h>
#include <linux/sizes.h>

#include <linux/platform_data/mtd-nand-omap2.h>

#define DEVICE_NAME

/* GPMC register offsets */
#define GPMC_REVISION
#define GPMC_SYSCONFIG
#define GPMC_SYSSTATUS
#define GPMC_IRQSTATUS
#define GPMC_IRQENABLE
#define GPMC_TIMEOUT_CONTROL
#define GPMC_ERR_ADDRESS
#define GPMC_ERR_TYPE
#define GPMC_CONFIG
#define GPMC_STATUS
#define GPMC_PREFETCH_CONFIG1
#define GPMC_PREFETCH_CONFIG2
#define GPMC_PREFETCH_CONTROL
#define GPMC_PREFETCH_STATUS
#define GPMC_ECC_CONFIG
#define GPMC_ECC_CONTROL
#define GPMC_ECC_SIZE_CONFIG
#define GPMC_ECC1_RESULT
#define GPMC_ECC_BCH_RESULT_0
#define GPMC_ECC_BCH_RESULT_1
#define GPMC_ECC_BCH_RESULT_2
#define GPMC_ECC_BCH_RESULT_3
#define GPMC_ECC_BCH_RESULT_4
#define GPMC_ECC_BCH_RESULT_5
#define GPMC_ECC_BCH_RESULT_6

/* GPMC ECC control settings */
#define GPMC_ECC_CTRL_ECCCLEAR
#define GPMC_ECC_CTRL_ECCDISABLE
#define GPMC_ECC_CTRL_ECCREG1
#define GPMC_ECC_CTRL_ECCREG2
#define GPMC_ECC_CTRL_ECCREG3
#define GPMC_ECC_CTRL_ECCREG4
#define GPMC_ECC_CTRL_ECCREG5
#define GPMC_ECC_CTRL_ECCREG6
#define GPMC_ECC_CTRL_ECCREG7
#define GPMC_ECC_CTRL_ECCREG8
#define GPMC_ECC_CTRL_ECCREG9

#define GPMC_CONFIG_LIMITEDADDRESS

#define GPMC_STATUS_EMPTYWRITEBUFFERSTATUS

#define GPMC_CONFIG2_CSEXTRADELAY
#define GPMC_CONFIG3_ADVEXTRADELAY
#define GPMC_CONFIG4_OEEXTRADELAY
#define GPMC_CONFIG4_WEEXTRADELAY
#define GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN
#define GPMC_CONFIG6_CYCLE2CYCLESAMECSEN

#define GPMC_CS0_OFFSET
#define GPMC_CS_SIZE
#define GPMC_BCH_SIZE

/*
 * The first 1MB of GPMC address space is typically mapped to
 * the internal ROM. Never allocate the first page, to
 * facilitate bug detection; even if we didn't boot from ROM.
 * As GPMC minimum partition size is 16MB we can only start from
 * there.
 */
#define GPMC_MEM_START
#define GPMC_MEM_END

#define GPMC_CHUNK_SHIFT
#define GPMC_SECTION_SHIFT

#define CS_NUM_SHIFT
#define ENABLE_PREFETCH
#define DMA_MPU_MODE

#define GPMC_REVISION_MAJOR(l)
#define GPMC_REVISION_MINOR(l)

#define GPMC_HAS_WR_ACCESS
#define GPMC_HAS_WR_DATA_MUX_BUS
#define GPMC_HAS_MUX_AAD

#define GPMC_NR_WAITPINS

#define GPMC_CS_CONFIG1
#define GPMC_CS_CONFIG2
#define GPMC_CS_CONFIG3
#define GPMC_CS_CONFIG4
#define GPMC_CS_CONFIG5
#define GPMC_CS_CONFIG6
#define GPMC_CS_CONFIG7
#define GPMC_CS_NAND_COMMAND
#define GPMC_CS_NAND_ADDRESS
#define GPMC_CS_NAND_DATA

/* Control Commands */
#define GPMC_CONFIG_RDY_BSY
#define GPMC_CONFIG_DEV_SIZE
#define GPMC_CONFIG_DEV_TYPE

#define GPMC_CONFIG_WAITPINPOLARITY(pin)
#define GPMC_CONFIG1_WRAPBURST_SUPP
#define GPMC_CONFIG1_READMULTIPLE_SUPP
#define GPMC_CONFIG1_READTYPE_ASYNC
#define GPMC_CONFIG1_READTYPE_SYNC
#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP
#define GPMC_CONFIG1_WRITETYPE_ASYNC
#define GPMC_CONFIG1_WRITETYPE_SYNC
#define GPMC_CONFIG1_CLKACTIVATIONTIME(val)
/** CLKACTIVATIONTIME Max Ticks */
#define GPMC_CONFIG1_CLKACTIVATIONTIME_MAX
#define GPMC_CONFIG1_PAGE_LEN(val)
/** ATTACHEDDEVICEPAGELENGTH Max Value */
#define GPMC_CONFIG1_ATTACHEDDEVICEPAGELENGTH_MAX
#define GPMC_CONFIG1_WAIT_READ_MON
#define GPMC_CONFIG1_WAIT_WRITE_MON
#define GPMC_CONFIG1_WAIT_MON_TIME(val)
/** WAITMONITORINGTIME Max Ticks */
#define GPMC_CONFIG1_WAITMONITORINGTIME_MAX
#define GPMC_CONFIG1_WAIT_PIN_SEL(val)
#define GPMC_CONFIG1_DEVICESIZE(val)
#define GPMC_CONFIG1_DEVICESIZE_16
/** DEVICESIZE Max Value */
#define GPMC_CONFIG1_DEVICESIZE_MAX
#define GPMC_CONFIG1_DEVICETYPE(val)
#define GPMC_CONFIG1_DEVICETYPE_NOR
#define GPMC_CONFIG1_MUXTYPE(val)
#define GPMC_CONFIG1_TIME_PARA_GRAN
#define GPMC_CONFIG1_FCLK_DIV(val)
#define GPMC_CONFIG1_FCLK_DIV2
#define GPMC_CONFIG1_FCLK_DIV3
#define GPMC_CONFIG1_FCLK_DIV4
#define GPMC_CONFIG7_CSVALID

#define GPMC_CONFIG7_BASEADDRESS_MASK
#define GPMC_CONFIG7_CSVALID_MASK
#define GPMC_CONFIG7_MASKADDRESS_OFFSET
#define GPMC_CONFIG7_MASKADDRESS_MASK
/* All CONFIG7 bits except reserved bits */
#define GPMC_CONFIG7_MASK

#define GPMC_DEVICETYPE_NOR
#define GPMC_DEVICETYPE_NAND
#define GPMC_CONFIG_WRITEPROTECT
#define WR_RD_PIN_MONITORING

/* ECC commands */
#define GPMC_ECC_READ
#define GPMC_ECC_WRITE
#define GPMC_ECC_READSYN

#define GPMC_NR_NAND_IRQS

enum gpmc_clk_domain {};

struct gpmc_cs_data {};

/* Structure to save gpmc cs context */
struct gpmc_cs_config {};

/*
 * Structure to save/restore gpmc context
 * to support core off on OMAP3
 */
struct omap3_gpmc_regs {};

struct gpmc_waitpin {};

struct gpmc_device {};

static struct irq_domain *gpmc_irq_domain;

static struct resource	gpmc_mem_root;
static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
static DEFINE_SPINLOCK(gpmc_mem_lock);
/* Define chip-selects as reserved by default until probe completes */
static unsigned int gpmc_cs_num =;
static unsigned int gpmc_nr_waitpins;
static unsigned int gpmc_capability;
static void __iomem *gpmc_base;

static struct clk *gpmc_l3_clk;

static irqreturn_t gpmc_handle_irq(int irq, void *dev);

static void gpmc_write_reg(int idx, u32 val)
{}

static u32 gpmc_read_reg(int idx)
{}

void gpmc_cs_write_reg(int cs, int idx, u32 val)
{}

static u32 gpmc_cs_read_reg(int cs, int idx)
{}

/* TODO: Add support for gpmc_fck to clock framework and use it */
static unsigned long gpmc_get_fclk_period(void)
{}

/**
 * gpmc_get_clk_period - get period of selected clock domain in ps
 * @cs: Chip Select Region.
 * @cd: Clock Domain.
 *
 * GPMC_CS_CONFIG1 GPMCFCLKDIVIDER for cs has to be setup
 * prior to calling this function with GPMC_CD_CLK.
 */
static unsigned long gpmc_get_clk_period(int cs, enum gpmc_clk_domain cd)
{}

static unsigned int gpmc_ns_to_clk_ticks(unsigned int time_ns, int cs,
					 enum gpmc_clk_domain cd)
{}

static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
{}

static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
{}

static unsigned int gpmc_clk_ticks_to_ns(unsigned int ticks, int cs,
					 enum gpmc_clk_domain cd)
{}

unsigned int gpmc_ticks_to_ns(unsigned int ticks)
{}

static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
{}

static unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
{}

static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
{}

static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
{}

#ifdef CONFIG_OMAP_GPMC_DEBUG
/**
 * get_gpmc_timing_reg - read a timing parameter and print DTS settings for it.
 * @cs:      Chip Select Region
 * @reg:     GPMC_CS_CONFIGn register offset.
 * @st_bit:  Start Bit
 * @end_bit: End Bit. Must be >= @st_bit.
 * @max:     Maximum parameter value (before optional @shift).
 *           If 0, maximum is as high as @st_bit and @end_bit allow.
 * @name:    DTS node name, w/o "gpmc,"
 * @cd:      Clock Domain of timing parameter.
 * @shift:   Parameter value left shifts @shift, which is then printed instead of value.
 * @raw:     Raw Format Option.
 *           raw format:  gpmc,name = <value>
 *           tick format: gpmc,name = <value> /&zwj;* x ns -- y ns; x ticks *&zwj;/
 *           Where x ns -- y ns result in the same tick value.
 *           When @max is exceeded, "invalid" is printed inside comment.
 * @noval:   Parameter values equal to 0 are not printed.
 * @return:  Specified timing parameter (after optional @shift).
 *
 */
static int get_gpmc_timing_reg(
	/* timing specifiers */
	int cs, int reg, int st_bit, int end_bit, int max,
	const char *name, const enum gpmc_clk_domain cd,
	/* value transform */
	int shift,
	/* format specifiers */
	bool raw, bool noval)
{}

#define GPMC_PRINT_CONFIG(cs, config)
#define GPMC_GET_RAW(reg, st, end, field)
#define GPMC_GET_RAW_MAX(reg, st, end, max, field)
#define GPMC_GET_RAW_BOOL(reg, st, end, field)
#define GPMC_GET_RAW_SHIFT_MAX(reg, st, end, shift, max, field)
#define GPMC_GET_TICKS(reg, st, end, field)
#define GPMC_GET_TICKS_CD(reg, st, end, field, cd)
#define GPMC_GET_TICKS_CD_MAX(reg, st, end, max, field, cd)

static void gpmc_show_regs(int cs, const char *desc)
{}

/*
 * Note that gpmc,wait-pin handing wrongly assumes bit 8 is available,
 * see commit c9fb809.
 */
static void gpmc_cs_show_timings(int cs, const char *desc)
{}
#else
static inline void gpmc_cs_show_timings(int cs, const char *desc)
{
}
#endif

/**
 * set_gpmc_timing_reg - set a single timing parameter for Chip Select Region.
 * Caller is expected to have initialized CONFIG1 GPMCFCLKDIVIDER
 * prior to calling this function with @cd equal to GPMC_CD_CLK.
 *
 * @cs:      Chip Select Region.
 * @reg:     GPMC_CS_CONFIGn register offset.
 * @st_bit:  Start Bit
 * @end_bit: End Bit. Must be >= @st_bit.
 * @max:     Maximum parameter value.
 *           If 0, maximum is as high as @st_bit and @end_bit allow.
 * @time:    Timing parameter in ns.
 * @cd:      Timing parameter clock domain.
 * @name:    Timing parameter name.
 * @return:  0 on success, -1 on error.
 */
static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, int max,
			       int time, enum gpmc_clk_domain cd, const char *name)
{}

/**
 * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based on WAITMONITORINGTIME
 * WAITMONITORINGTIME will be _at least_ as long as desired, i.e.
 * read  --> don't sample bus too early
 * write --> data is longer on bus
 *
 * Formula:
 * gpmc_clk_div + 1 = ceil(ceil(waitmonitoringtime_ns / gpmc_fclk_ns)
 *                    / waitmonitoring_ticks)
 * WAITMONITORINGTIME resulting in 0 or 1 tick with div = 1 are caught by
 * div <= 0 check.
 *
 * @wait_monitoring: WAITMONITORINGTIME in ns.
 * @return:          -1 on failure to scale, else proper divider > 0.
 */
static int gpmc_calc_waitmonitoring_divider(unsigned int wait_monitoring)
{}

/**
 * gpmc_calc_divider - calculate GPMC_FCLK divider for sync_clk GPMC_CLK period.
 * @sync_clk: GPMC_CLK period in ps.
 * @return:   Returns at least 1 if GPMC_FCLK can be divided to GPMC_CLK.
 *            Else, returns -1.
 */
int gpmc_calc_divider(unsigned int sync_clk)
{}

/**
 * gpmc_cs_set_timings - program timing parameters for Chip Select Region.
 * @cs:     Chip Select Region.
 * @t:      GPMC timing parameters.
 * @s:      GPMC timing settings.
 * @return: 0 on success, -1 on error.
 */
int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
			const struct gpmc_settings *s)
{}

static int gpmc_cs_set_memconf(int cs, u32 base, u32 size)
{}

static void gpmc_cs_enable_mem(int cs)
{}

static void gpmc_cs_disable_mem(int cs)
{}

static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
{}

static int gpmc_cs_mem_enabled(int cs)
{}

static void gpmc_cs_set_reserved(int cs, int reserved)
{}

static bool gpmc_cs_reserved(int cs)
{}

static unsigned long gpmc_mem_align(unsigned long size)
{}

static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
{}

static int gpmc_cs_delete_mem(int cs)
{}

int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
{}
EXPORT_SYMBOL();

void gpmc_cs_free(int cs)
{}
EXPORT_SYMBOL();

static bool gpmc_is_valid_waitpin(u32 waitpin)
{}

static int gpmc_alloc_waitpin(struct gpmc_device *gpmc,
			      struct gpmc_settings *p)
{}

static void gpmc_free_waitpin(struct gpmc_device *gpmc,
			      int wait_pin)
{}

/**
 * gpmc_configure - write request to configure gpmc
 * @cmd: command type
 * @wval: value to write
 * @return status of the operation
 */
int gpmc_configure(int cmd, int wval)
{}
EXPORT_SYMBOL();

static bool gpmc_nand_writebuffer_empty(void)
{}

static struct gpmc_nand_ops nand_ops =;

/**
 * gpmc_omap_get_nand_ops - Get the GPMC NAND interface
 * @reg: the GPMC NAND register map exclusive for NAND use.
 * @cs: GPMC chip select number on which the NAND sits. The
 *      register map returned will be specific to this chip select.
 *
 * Returns NULL on error e.g. invalid cs.
 */
struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *reg, int cs)
{}
EXPORT_SYMBOL_GPL();

static void gpmc_omap_onenand_calc_sync_timings(struct gpmc_timings *t,
						struct gpmc_settings *s,
						int freq, int latency)
{}

int gpmc_omap_onenand_set_timings(struct device *dev, int cs, int freq,
				  int latency,
				  struct gpmc_onenand_info *info)
{}
EXPORT_SYMBOL_GPL();

int gpmc_get_client_irq(unsigned int irq_config)
{}

static int gpmc_irq_endis(unsigned long hwirq, bool endis)
{}

static void gpmc_irq_disable(struct irq_data *p)
{}

static void gpmc_irq_enable(struct irq_data *p)
{}

static void gpmc_irq_mask(struct irq_data *d)
{}

static void gpmc_irq_unmask(struct irq_data *d)
{}

static void gpmc_irq_edge_config(unsigned long hwirq, bool rising_edge)
{}

static void gpmc_irq_ack(struct irq_data *d)
{}

static int gpmc_irq_set_type(struct irq_data *d, unsigned int trigger)
{}

static int gpmc_irq_map(struct irq_domain *d, unsigned int virq,
			irq_hw_number_t hw)
{}

static const struct irq_domain_ops gpmc_irq_domain_ops =;

static irqreturn_t gpmc_handle_irq(int irq, void *data)
{}

static int gpmc_setup_irq(struct gpmc_device *gpmc)
{}

static int gpmc_free_irq(struct gpmc_device *gpmc)
{}

static void gpmc_mem_exit(void)
{}

static void gpmc_mem_init(struct gpmc_device *gpmc)
{}

static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
{}

/* XXX: can the cycles be avoided ? */
static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
				       struct gpmc_device_timings *dev_t,
				       bool mux)
{}

static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
					struct gpmc_device_timings *dev_t,
					bool mux)
{}

static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
					struct gpmc_device_timings *dev_t,
					bool mux)
{}

static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
					 struct gpmc_device_timings *dev_t,
					 bool mux)
{}

static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
			struct gpmc_device_timings *dev_t)
{}

static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
				    struct gpmc_device_timings *dev_t,
				    bool sync)
{}

/*
 * TODO: remove this function once all peripherals are confirmed to
 * work with generic timing. Simultaneously gpmc_cs_set_timings()
 * has to be modified to handle timings in ps instead of ns
 */
static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
{}

int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
		      struct gpmc_settings *gpmc_s,
		      struct gpmc_device_timings *dev_t)
{}

/**
 * gpmc_cs_program_settings - programs non-timing related settings
 * @cs:		GPMC chip-select to program
 * @p:		pointer to GPMC settings structure
 *
 * Programs non-timing related settings for a GPMC chip-select, such as
 * bus-width, burst configuration, etc. Function should be called once
 * for each chip-select that is being used and must be called before
 * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
 * register will be initialised to zero by this function. Returns 0 on
 * success and appropriate negative error code on failure.
 */
int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
{}

#ifdef CONFIG_OF
static void gpmc_cs_set_name(int cs, const char *name)
{}

static const char *gpmc_cs_get_name(int cs)
{}

/**
 * gpmc_cs_remap - remaps a chip-select physical base address
 * @cs:		chip-select to remap
 * @base:	physical base address to re-map chip-select to
 *
 * Re-maps a chip-select to a new physical base address specified by
 * "base". Returns 0 on success and appropriate negative error code
 * on failure.
 */
static int gpmc_cs_remap(int cs, u32 base)
{}

/**
 * gpmc_read_settings_dt - read gpmc settings from device-tree
 * @np:		pointer to device-tree node for a gpmc child device
 * @p:		pointer to gpmc settings structure
 *
 * Reads the GPMC settings for a GPMC child device from device-tree and
 * stores them in the GPMC settings structure passed. The GPMC settings
 * structure is initialised to zero by this function and so any
 * previously stored settings will be cleared.
 */
void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
{}

static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
						struct gpmc_timings *gpmc_t)
{}

/**
 * gpmc_probe_generic_child - configures the gpmc for a child device
 * @pdev:	pointer to gpmc platform device
 * @child:	pointer to device-tree node for child device
 *
 * Allocates and configures a GPMC chip-select for a child device.
 * Returns 0 on success and appropriate negative error code on failure.
 */
static int gpmc_probe_generic_child(struct platform_device *pdev,
				struct device_node *child)
{}

static const struct of_device_id gpmc_dt_ids[];

static int gpmc_probe_dt(struct platform_device *pdev)
{}

static void gpmc_probe_dt_children(struct platform_device *pdev)
{}
#else
void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
{
	memset(p, 0, sizeof(*p));
}
static int gpmc_probe_dt(struct platform_device *pdev)
{
	return 0;
}

static void gpmc_probe_dt_children(struct platform_device *pdev)
{
}
#endif /* CONFIG_OF */

static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{}

static int gpmc_gpio_direction_input(struct gpio_chip *chip,
				     unsigned int offset)
{}

static int gpmc_gpio_direction_output(struct gpio_chip *chip,
				      unsigned int offset, int value)
{}

static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset,
			  int value)
{}

static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset)
{}

static int gpmc_gpio_init(struct gpmc_device *gpmc)
{}

static void omap3_gpmc_save_context(struct gpmc_device *gpmc)
{}

static void omap3_gpmc_restore_context(struct gpmc_device *gpmc)
{}

static int omap_gpmc_context_notifier(struct notifier_block *nb,
				      unsigned long cmd, void *v)
{}

static int gpmc_probe(struct platform_device *pdev)
{}

static void gpmc_remove(struct platform_device *pdev)
{}

#ifdef CONFIG_PM_SLEEP
static int gpmc_suspend(struct device *dev)
{}

static int gpmc_resume(struct device *dev)
{}
#endif

static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);

#ifdef CONFIG_OF
static const struct of_device_id gpmc_dt_ids[] =;
MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
#endif

static struct platform_driver gpmc_driver =;

module_platform_driver();

MODULE_DESCRIPTION();
MODULE_LICENSE();