diff options
author | 2023-02-21 18:24:12 -0800 | |
---|---|---|
committer | 2023-02-21 18:24:12 -0800 | |
commit | 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 (patch) | |
tree | cc5c2d0a898769fd59549594fedb3ee6f84e59a0 /drivers/mtd/nand/raw/nand_legacy.c | |
download | linux-5b7c4cabbb65f5c469464da6c5f614cbd7f730f2.tar.gz linux-5b7c4cabbb65f5c469464da6c5f614cbd7f730f2.zip |
Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-nextgrafted
Pull networking updates from Jakub Kicinski:
"Core:
- Add dedicated kmem_cache for typical/small skb->head, avoid having
to access struct page at kfree time, and improve memory use.
- Introduce sysctl to set default RPS configuration for new netdevs.
- Define Netlink protocol specification format which can be used to
describe messages used by each family and auto-generate parsers.
Add tools for generating kernel data structures and uAPI headers.
- Expose all net/core sysctls inside netns.
- Remove 4s sleep in netpoll if carrier is instantly detected on
boot.
- Add configurable limit of MDB entries per port, and port-vlan.
- Continue populating drop reasons throughout the stack.
- Retire a handful of legacy Qdiscs and classifiers.
Protocols:
- Support IPv4 big TCP (TSO frames larger than 64kB).
- Add IP_LOCAL_PORT_RANGE socket option, to control local port range
on socket by socket basis.
- Track and report in procfs number of MPTCP sockets used.
- Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path
manager.
- IPv6: don't check net.ipv6.route.max_size and rely on garbage
collection to free memory (similarly to IPv4).
- Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986).
- ICMP: add per-rate limit counters.
- Add support for user scanning requests in ieee802154.
- Remove static WEP support.
- Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate
reporting.
- WiFi 7 EHT channel puncturing support (client & AP).
BPF:
- Add a rbtree data structure following the "next-gen data structure"
precedent set by recently added linked list, that is, by using
kfunc + kptr instead of adding a new BPF map type.
- Expose XDP hints via kfuncs with initial support for RX hash and
timestamp metadata.
- Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to
better support decap on GRE tunnel devices not operating in collect
metadata.
- Improve x86 JIT's codegen for PROBE_MEM runtime error checks.
- Remove the need for trace_printk_lock for bpf_trace_printk and
bpf_trace_vprintk helpers.
- Extend libbpf's bpf_tracing.h support for tracing arguments of
kprobes/uprobes and syscall as a special case.
- Significantly reduce the search time for module symbols by
livepatch and BPF.
- Enable cpumasks to be used as kptrs, which is useful for tracing
programs tracking which tasks end up running on which CPUs in
different time intervals.
- Add support for BPF trampoline on s390x and riscv64.
- Add capability to export the XDP features supported by the NIC.
- Add __bpf_kfunc tag for marking kernel functions as kfuncs.
- Add cgroup.memory=nobpf kernel parameter option to disable BPF
memory accounting for container environments.
Netfilter:
- Remove the CLUSTERIP target. It has been marked as obsolete for
years, and we still have WARN splats wrt races of the out-of-band
/proc interface installed by this target.
- Add 'destroy' commands to nf_tables. They are identical to the
existing 'delete' commands, but do not return an error if the
referenced object (set, chain, rule...) did not exist.
Driver API:
- Improve cpumask_local_spread() locality to help NICs set the right
IRQ affinity on AMD platforms.
- Separate C22 and C45 MDIO bus transactions more clearly.
- Introduce new DCB table to control DSCP rewrite on egress.
- Support configuration of Physical Layer Collision Avoidance (PLCA)
Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of
shared medium Ethernet.
- Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing
preemption of low priority frames by high priority frames.
- Add support for controlling MACSec offload using netlink SET.
- Rework devlink instance refcounts to allow registration and
de-registration under the instance lock. Split the code into
multiple files, drop some of the unnecessarily granular locks and
factor out common parts of netlink operation handling.
- Add TX frame aggregation parameters (for USB drivers).
- Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning
messages with notifications for debug.
- Allow offloading of UDP NEW connections via act_ct.
- Add support for per action HW stats in TC.
- Support hardware miss to TC action (continue processing in SW from
a specific point in the action chain).
- Warn if old Wireless Extension user space interface is used with
modern cfg80211/mac80211 drivers. Do not support Wireless
Extensions for Wi-Fi 7 devices at all. Everyone should switch to
using nl80211 interface instead.
- Improve the CAN bit timing configuration. Use extack to return
error messages directly to user space, update the SJW handling,
including the definition of a new default value that will benefit
CAN-FD controllers, by increasing their oscillator tolerance.
New hardware / drivers:
- Ethernet:
- nVidia BlueField-3 support (control traffic driver)
- Ethernet support for imx93 SoCs
- Motorcomm yt8531 gigabit Ethernet PHY
- onsemi NCN26000 10BASE-T1S PHY (with support for PLCA)
- Microchip LAN8841 PHY (incl. cable diagnostics and PTP)
- Amlogic gxl MDIO mux
- WiFi:
- RealTek RTL8188EU (rtl8xxxu)
- Qualcomm Wi-Fi 7 devices (ath12k)
- CAN:
- Renesas R-Car V4H
Drivers:
- Bluetooth:
- Set Per Platform Antenna Gain (PPAG) for Intel controllers.
- Ethernet NICs:
- Intel (1G, igc):
- support TSN / Qbv / packet scheduling features of i226 model
- Intel (100G, ice):
- use GNSS subsystem instead of TTY
- multi-buffer XDP support
- extend support for GPIO pins to E823 devices
- nVidia/Mellanox:
- update the shared buffer configuration on PFC commands
- implement PTP adjphase function for HW offset control
- TC support for Geneve and GRE with VF tunnel offload
- more efficient crypto key management method
- multi-port eswitch support
- Netronome/Corigine:
- add DCB IEEE support
- support IPsec offloading for NFP3800
- Freescale/NXP (enetc):
- support XDP_REDIRECT for XDP non-linear buffers
- improve reconfig, avoid link flap and waiting for idle
- support MAC Merge layer
- Other NICs:
- sfc/ef100: add basic devlink support for ef100
- ionic: rx_push mode operation (writing descriptors via MMIO)
- bnxt: use the auxiliary bus abstraction for RDMA
- r8169: disable ASPM and reset bus in case of tx timeout
- cpsw: support QSGMII mode for J721e CPSW9G
- cpts: support pulse-per-second output
- ngbe: add an mdio bus driver
- usbnet: optimize usbnet_bh() by avoiding unnecessary queuing
- r8152: handle devices with FW with NCM support
- amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation
- virtio-net: support multi buffer XDP
- virtio/vsock: replace virtio_vsock_pkt with sk_buff
- tsnep: XDP support
- Ethernet high-speed switches:
- nVidia/Mellanox (mlxsw):
- add support for latency TLV (in FW control messages)
- Microchip (sparx5):
- separate explicit and implicit traffic forwarding rules, make
the implicit rules always active
- add support for egress DSCP rewrite
- IS0 VCAP support (Ingress Classification)
- IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS
etc.)
- ES2 VCAP support (Egress Access Control)
- support for Per-Stream Filtering and Policing (802.1Q,
8.6.5.1)
- Ethernet embedded switches:
- Marvell (mv88e6xxx):
- add MAB (port auth) offload support
- enable PTP receive for mv88e6390
- NXP (ocelot):
- support MAC Merge layer
- support for the the vsc7512 internal copper phys
- Microchip:
- lan9303: convert to PHYLINK
- lan966x: support TC flower filter statistics
- lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x
- lan937x: support Credit Based Shaper configuration
- ksz9477: support Energy Efficient Ethernet
- other:
- qca8k: convert to regmap read/write API, use bulk operations
- rswitch: Improve TX timestamp accuracy
- Intel WiFi (iwlwifi):
- EHT (Wi-Fi 7) rate reporting
- STEP equalizer support: transfer some STEP (connection to radio
on platforms with integrated wifi) related parameters from the
BIOS to the firmware.
- Qualcomm 802.11ax WiFi (ath11k):
- IPQ5018 support
- Fine Timing Measurement (FTM) responder role support
- channel 177 support
- MediaTek WiFi (mt76):
- per-PHY LED support
- mt7996: EHT (Wi-Fi 7) support
- Wireless Ethernet Dispatch (WED) reset support
- switch to using page pool allocator
- RealTek WiFi (rtw89):
- support new version of Bluetooth co-existance
- Mobile:
- rmnet: support TX aggregation"
* tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits)
page_pool: add a comment explaining the fragment counter usage
net: ethtool: fix __ethtool_dev_mm_supported() implementation
ethtool: pse-pd: Fix double word in comments
xsk: add linux/vmalloc.h to xsk.c
sefltests: netdevsim: wait for devlink instance after netns removal
selftest: fib_tests: Always cleanup before exit
net/mlx5e: Align IPsec ASO result memory to be as required by hardware
net/mlx5e: TC, Set CT miss to the specific ct action instance
net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG
net/mlx5: Refactor tc miss handling to a single function
net/mlx5: Kconfig: Make tc offload depend on tc skb extension
net/sched: flower: Support hardware miss to tc action
net/sched: flower: Move filter handle initialization earlier
net/sched: cls_api: Support hardware miss to tc action
net/sched: Rename user cookie and act cookie
sfc: fix builds without CONFIG_RTC_LIB
sfc: clean up some inconsistent indentings
net/mlx4_en: Introduce flexible array to silence overflow warning
net: lan966x: Fix possible deadlock inside PTP
net/ulp: Remove redundant ->clone() test in inet_clone_ulp().
...
Diffstat (limited to 'drivers/mtd/nand/raw/nand_legacy.c')
-rw-r--r-- | drivers/mtd/nand/raw/nand_legacy.c | 644 |
1 files changed, 644 insertions, 0 deletions
diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c new file mode 100644 index 000000000..743792edf --- /dev/null +++ b/drivers/mtd/nand/raw/nand_legacy.c @@ -0,0 +1,644 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * + * Credits: + * David Woodhouse for adding multichip support + * + * Aleph One Ltd. and Toby Churchill Ltd. for supporting the + * rework for 2K page size chips + * + * This file contains all legacy helpers/code that should be removed + * at some point. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/nmi.h> + +#include "internals.h" + +/** + * nand_read_byte - [DEFAULT] read one byte from the chip + * @chip: NAND chip object + * + * Default read function for 8bit buswidth + */ +static uint8_t nand_read_byte(struct nand_chip *chip) +{ + return readb(chip->legacy.IO_ADDR_R); +} + +/** + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip + * @chip: NAND chip object + * + * Default read function for 16bit buswidth with endianness conversion. + * + */ +static uint8_t nand_read_byte16(struct nand_chip *chip) +{ + return (uint8_t) cpu_to_le16(readw(chip->legacy.IO_ADDR_R)); +} + +/** + * nand_select_chip - [DEFAULT] control CE line + * @chip: NAND chip object + * @chipnr: chipnumber to select, -1 for deselect + * + * Default select function for 1 chip devices. + */ +static void nand_select_chip(struct nand_chip *chip, int chipnr) +{ + switch (chipnr) { + case -1: + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + 0 | NAND_CTRL_CHANGE); + break; + case 0: + break; + + default: + BUG(); + } +} + +/** + * nand_write_byte - [DEFAULT] write single byte to chip + * @chip: NAND chip object + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] + */ +static void nand_write_byte(struct nand_chip *chip, uint8_t byte) +{ + chip->legacy.write_buf(chip, &byte, 1); +} + +/** + * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16 + * @chip: NAND chip object + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] on a 16-bit wide chip. + */ +static void nand_write_byte16(struct nand_chip *chip, uint8_t byte) +{ + uint16_t word = byte; + + /* + * It's not entirely clear what should happen to I/O[15:8] when writing + * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads: + * + * When the host supports a 16-bit bus width, only data is + * transferred at the 16-bit width. All address and command line + * transfers shall use only the lower 8-bits of the data bus. During + * command transfers, the host may place any value on the upper + * 8-bits of the data bus. During address transfers, the host shall + * set the upper 8-bits of the data bus to 00h. + * + * One user of the write_byte callback is nand_set_features. The + * four parameters are specified to be written to I/O[7:0], but this is + * neither an address nor a command transfer. Let's assume a 0 on the + * upper I/O lines is OK. + */ + chip->legacy.write_buf(chip, (uint8_t *)&word, 2); +} + +/** + * nand_write_buf - [DEFAULT] write buffer to chip + * @chip: NAND chip object + * @buf: data buffer + * @len: number of bytes to write + * + * Default write function for 8bit buswidth. + */ +static void nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) +{ + iowrite8_rep(chip->legacy.IO_ADDR_W, buf, len); +} + +/** + * nand_read_buf - [DEFAULT] read chip data into buffer + * @chip: NAND chip object + * @buf: buffer to store date + * @len: number of bytes to read + * + * Default read function for 8bit buswidth. + */ +static void nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len) +{ + ioread8_rep(chip->legacy.IO_ADDR_R, buf, len); +} + +/** + * nand_write_buf16 - [DEFAULT] write buffer to chip + * @chip: NAND chip object + * @buf: data buffer + * @len: number of bytes to write + * + * Default write function for 16bit buswidth. + */ +static void nand_write_buf16(struct nand_chip *chip, const uint8_t *buf, + int len) +{ + u16 *p = (u16 *) buf; + + iowrite16_rep(chip->legacy.IO_ADDR_W, p, len >> 1); +} + +/** + * nand_read_buf16 - [DEFAULT] read chip data into buffer + * @chip: NAND chip object + * @buf: buffer to store date + * @len: number of bytes to read + * + * Default read function for 16bit buswidth. + */ +static void nand_read_buf16(struct nand_chip *chip, uint8_t *buf, int len) +{ + u16 *p = (u16 *) buf; + + ioread16_rep(chip->legacy.IO_ADDR_R, p, len >> 1); +} + +/** + * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. + * @chip: NAND chip object + * @timeo: Timeout + * + * Helper function for nand_wait_ready used when needing to wait in interrupt + * context. + */ +static void panic_nand_wait_ready(struct nand_chip *chip, unsigned long timeo) +{ + int i; + + /* Wait for the device to get ready */ + for (i = 0; i < timeo; i++) { + if (chip->legacy.dev_ready(chip)) + break; + touch_softlockup_watchdog(); + mdelay(1); + } +} + +/** + * nand_wait_ready - [GENERIC] Wait for the ready pin after commands. + * @chip: NAND chip object + * + * Wait for the ready pin after a command, and warn if a timeout occurs. + */ +void nand_wait_ready(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned long timeo = 400; + + if (mtd->oops_panic_write) + return panic_nand_wait_ready(chip, timeo); + + /* Wait until command is processed or timeout occurs */ + timeo = jiffies + msecs_to_jiffies(timeo); + do { + if (chip->legacy.dev_ready(chip)) + return; + cond_resched(); + } while (time_before(jiffies, timeo)); + + if (!chip->legacy.dev_ready(chip)) + pr_warn_ratelimited("timeout while waiting for chip to become ready\n"); +} +EXPORT_SYMBOL_GPL(nand_wait_ready); + +/** + * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands. + * @chip: NAND chip object + * @timeo: Timeout in ms + * + * Wait for status ready (i.e. command done) or timeout. + */ +static void nand_wait_status_ready(struct nand_chip *chip, unsigned long timeo) +{ + int ret; + + timeo = jiffies + msecs_to_jiffies(timeo); + do { + u8 status; + + ret = nand_read_data_op(chip, &status, sizeof(status), true, + false); + if (ret) + return; + + if (status & NAND_STATUS_READY) + break; + touch_softlockup_watchdog(); + } while (time_before(jiffies, timeo)); +}; + +/** + * nand_command - [DEFAULT] Send command to NAND device + * @chip: NAND chip object + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + * + * Send command to NAND device. This function is used for small page devices + * (512 Bytes per page). + */ +static void nand_command(struct nand_chip *chip, unsigned int command, + int column, int page_addr) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; + + /* Write out the command to the device */ + if (command == NAND_CMD_SEQIN) { + int readcmd; + + if (column >= mtd->writesize) { + /* OOB area */ + column -= mtd->writesize; + readcmd = NAND_CMD_READOOB; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + readcmd = NAND_CMD_READ0; + } else { + column -= 256; + readcmd = NAND_CMD_READ1; + } + chip->legacy.cmd_ctrl(chip, readcmd, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + } + if (command != NAND_CMD_NONE) + chip->legacy.cmd_ctrl(chip, command, ctrl); + + /* Address cycle, when necessary */ + ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) + column >>= 1; + chip->legacy.cmd_ctrl(chip, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + } + if (page_addr != -1) { + chip->legacy.cmd_ctrl(chip, page_addr, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + chip->legacy.cmd_ctrl(chip, page_addr >> 8, ctrl); + if (chip->options & NAND_ROW_ADDR_3) + chip->legacy.cmd_ctrl(chip, page_addr >> 16, ctrl); + } + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Program and erase have their own busy handlers status and sequential + * in needs no delay + */ + switch (command) { + + case NAND_CMD_NONE: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + case NAND_CMD_READID: + case NAND_CMD_SET_FEATURES: + return; + + case NAND_CMD_RESET: + if (chip->legacy.dev_ready) + break; + udelay(chip->legacy.chip_delay); + chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(chip, 250); + return; + + /* This applies to read commands */ + case NAND_CMD_READ0: + /* + * READ0 is sometimes used to exit GET STATUS mode. When this + * is the case no address cycles are requested, and we can use + * this information to detect that we should not wait for the + * device to be ready. + */ + if (column == -1 && page_addr == -1) + return; + fallthrough; + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + if (!chip->legacy.dev_ready) { + udelay(chip->legacy.chip_delay); + return; + } + } + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(100); + + nand_wait_ready(chip); +} + +static void nand_ccs_delay(struct nand_chip *chip) +{ + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + + /* + * The controller already takes care of waiting for tCCS when the RNDIN + * or RNDOUT command is sent, return directly. + */ + if (!(chip->options & NAND_WAIT_TCCS)) + return; + + /* + * Wait tCCS_min if it is correctly defined, otherwise wait 500ns + * (which should be safe for all NANDs). + */ + if (!IS_ERR(sdr) && nand_controller_can_setup_interface(chip)) + ndelay(sdr->tCCS_min / 1000); + else + ndelay(500); +} + +/** + * nand_command_lp - [DEFAULT] Send command to NAND large page device + * @chip: NAND chip object + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + * + * Send command to NAND device. This is the version for the new large page + * devices. We don't have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + */ +static void nand_command_lp(struct nand_chip *chip, unsigned int command, + int column, int page_addr) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* Emulate NAND_CMD_READOOB */ + if (command == NAND_CMD_READOOB) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Command latch cycle */ + if (command != NAND_CMD_NONE) + chip->legacy.cmd_ctrl(chip, command, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + + if (column != -1 || page_addr != -1) { + int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; + + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) + column >>= 1; + chip->legacy.cmd_ctrl(chip, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + + /* Only output a single addr cycle for 8bits opcodes. */ + if (!nand_opcode_8bits(command)) + chip->legacy.cmd_ctrl(chip, column >> 8, ctrl); + } + if (page_addr != -1) { + chip->legacy.cmd_ctrl(chip, page_addr, ctrl); + chip->legacy.cmd_ctrl(chip, page_addr >> 8, + NAND_NCE | NAND_ALE); + if (chip->options & NAND_ROW_ADDR_3) + chip->legacy.cmd_ctrl(chip, page_addr >> 16, + NAND_NCE | NAND_ALE); + } + } + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Program and erase have their own busy handlers status, sequential + * in and status need no delay. + */ + switch (command) { + + case NAND_CMD_NONE: + case NAND_CMD_CACHEDPROG: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + case NAND_CMD_READID: + case NAND_CMD_SET_FEATURES: + return; + + case NAND_CMD_RNDIN: + nand_ccs_delay(chip); + return; + + case NAND_CMD_RESET: + if (chip->legacy.dev_ready) + break; + udelay(chip->legacy.chip_delay); + chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(chip, 250); + return; + + case NAND_CMD_RNDOUT: + /* No ready / busy check necessary */ + chip->legacy.cmd_ctrl(chip, NAND_CMD_RNDOUTSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + nand_ccs_delay(chip); + return; + + case NAND_CMD_READ0: + /* + * READ0 is sometimes used to exit GET STATUS mode. When this + * is the case no address cycles are requested, and we can use + * this information to detect that READSTART should not be + * issued. + */ + if (column == -1 && page_addr == -1) + return; + + chip->legacy.cmd_ctrl(chip, NAND_CMD_READSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + fallthrough; /* This applies to read commands */ + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay. + */ + if (!chip->legacy.dev_ready) { + udelay(chip->legacy.chip_delay); + return; + } + } + + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(100); + + nand_wait_ready(chip); +} + +/** + * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP + * @chip: nand chip info structure + * @addr: feature address. + * @subfeature_param: the subfeature parameters, a four bytes array. + * + * Should be used by NAND controller drivers that do not support the SET/GET + * FEATURES operations. + */ +int nand_get_set_features_notsupp(struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + return -ENOTSUPP; +} +EXPORT_SYMBOL(nand_get_set_features_notsupp); + +/** + * nand_wait - [DEFAULT] wait until the command is done + * @chip: NAND chip structure + * + * Wait for command done. This applies to erase and program only. + */ +static int nand_wait(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned long timeo = 400; + u8 status; + int ret; + + /* + * Apply this short delay always to ensure that we do wait tWB in any + * case on any machine. + */ + ndelay(100); + + ret = nand_status_op(chip, NULL); + if (ret) + return ret; + + if (mtd->oops_panic_write) { + panic_nand_wait(chip, timeo); + } else { + timeo = jiffies + msecs_to_jiffies(timeo); + do { + if (chip->legacy.dev_ready) { + if (chip->legacy.dev_ready(chip)) + break; + } else { + ret = nand_read_data_op(chip, &status, + sizeof(status), true, + false); + if (ret) + return ret; + + if (status & NAND_STATUS_READY) + break; + } + cond_resched(); + } while (time_before(jiffies, timeo)); + } + + ret = nand_read_data_op(chip, &status, sizeof(status), true, false); + if (ret) + return ret; + + /* This can happen if in case of timeout or buggy dev_ready */ + WARN_ON(!(status & NAND_STATUS_READY)); + return status; +} + +void nand_legacy_set_defaults(struct nand_chip *chip) +{ + unsigned int busw = chip->options & NAND_BUSWIDTH_16; + + if (nand_has_exec_op(chip)) + return; + + /* check for proper chip_delay setup, set 20us if not */ + if (!chip->legacy.chip_delay) + chip->legacy.chip_delay = 20; + + /* check, if a user supplied command function given */ + if (!chip->legacy.cmdfunc) + chip->legacy.cmdfunc = nand_command; + + /* check, if a user supplied wait function given */ + if (chip->legacy.waitfunc == NULL) + chip->legacy.waitfunc = nand_wait; + + if (!chip->legacy.select_chip) + chip->legacy.select_chip = nand_select_chip; + + /* If called twice, pointers that depend on busw may need to be reset */ + if (!chip->legacy.read_byte || chip->legacy.read_byte == nand_read_byte) + chip->legacy.read_byte = busw ? nand_read_byte16 : nand_read_byte; + if (!chip->legacy.write_buf || chip->legacy.write_buf == nand_write_buf) + chip->legacy.write_buf = busw ? nand_write_buf16 : nand_write_buf; + if (!chip->legacy.write_byte || chip->legacy.write_byte == nand_write_byte) + chip->legacy.write_byte = busw ? nand_write_byte16 : nand_write_byte; + if (!chip->legacy.read_buf || chip->legacy.read_buf == nand_read_buf) + chip->legacy.read_buf = busw ? nand_read_buf16 : nand_read_buf; +} + +void nand_legacy_adjust_cmdfunc(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* Do not replace user supplied command function! */ + if (mtd->writesize > 512 && chip->legacy.cmdfunc == nand_command) + chip->legacy.cmdfunc = nand_command_lp; +} + +int nand_legacy_check_hooks(struct nand_chip *chip) +{ + /* + * ->legacy.cmdfunc() is legacy and will only be used if ->exec_op() is + * not populated. + */ + if (nand_has_exec_op(chip)) + return 0; + + /* + * Default functions assigned for ->legacy.cmdfunc() and + * ->legacy.select_chip() both expect ->legacy.cmd_ctrl() to be + * populated. + */ + if ((!chip->legacy.cmdfunc || !chip->legacy.select_chip) && + !chip->legacy.cmd_ctrl) { + pr_err("->legacy.cmd_ctrl() should be provided\n"); + return -EINVAL; + } + + return 0; +} |