Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * LPDDR flash memory device operations. This module provides read, write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * erase, lock/unlock support for LPDDR flash memories
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * (C) 2008 Korolev Alexey <akorolev@infradead.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Many thanks to Roman Borisov for initial enabling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * Implement VPP management
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * Implement XIP support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * Implement OTP support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/mtd/pfow.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/mtd/qinfo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 					size_t *retlen, u_char *buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 				size_t len, size_t *retlen, const u_char *buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 				unsigned long count, loff_t to, size_t *retlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 			size_t *retlen, void **mtdbuf, resource_size_t *phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) static int lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) static int get_chip(struct map_info *map, struct flchip *chip, int mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) static int chip_ready(struct map_info *map, struct flchip *chip, int mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) static void put_chip(struct map_info *map, struct flchip *chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) struct mtd_info *lpddr_cmdset(struct map_info *map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	struct flchip_shared *shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	struct flchip *chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	int numchips;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	int i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	if (!mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	mtd->priv = map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	mtd->type = MTD_NORFLASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	/* Fill in the default mtd operations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	mtd->_read = lpddr_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	mtd->type = MTD_NORFLASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	mtd->flags = MTD_CAP_NORFLASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	mtd->flags &= ~MTD_BIT_WRITEABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	mtd->_erase = lpddr_erase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	mtd->_write = lpddr_write_buffers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	mtd->_writev = lpddr_writev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	mtd->_lock = lpddr_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	mtd->_unlock = lpddr_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	if (map_is_linear(map)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 		mtd->_point = lpddr_point;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 		mtd->_unpoint = lpddr_unpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	mtd->size = 1 << lpddr->qinfo->DevSizeShift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	mtd->writesize = 1 << lpddr->qinfo->BufSizeShift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	shared = kmalloc_array(lpddr->numchips, sizeof(struct flchip_shared),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 						GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	if (!shared) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		kfree(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	chip = &lpddr->chips[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	numchips = lpddr->numchips / lpddr->qinfo->HWPartsNum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	for (i = 0; i < numchips; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		shared[i].writing = shared[i].erasing = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		mutex_init(&shared[i].lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		for (j = 0; j < lpddr->qinfo->HWPartsNum; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 			*chip = lpddr->chips[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 			chip->start += j << lpddr->chipshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 			chip->oldstate = chip->state = FL_READY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 			chip->priv = &shared[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 			/* those should be reset too since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 			   they create memory references. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 			init_waitqueue_head(&chip->wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 			mutex_init(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 			chip++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	return mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) EXPORT_SYMBOL(lpddr_cmdset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) static void print_drs_error(unsigned int dsr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	int prog_status = (dsr & DSR_RPS) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	if (!(dsr & DSR_AVAILABLE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		pr_notice("DSR.15: (0) Device not Available\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	if ((prog_status & 0x03) == 0x03)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		pr_notice("DSR.9,8: (11) Attempt to program invalid half with 41h command\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	else if (prog_status & 0x02)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		pr_notice("DSR.9,8: (10) Object Mode Program attempt in region with Control Mode data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	else if (prog_status &  0x01)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		pr_notice("DSR.9,8: (01) Program attempt in region with Object Mode data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	if (!(dsr & DSR_READY_STATUS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		pr_notice("DSR.7: (0) Device is Busy\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	if (dsr & DSR_ESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		pr_notice("DSR.6: (1) Erase Suspended\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	if (dsr & DSR_ERASE_STATUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		pr_notice("DSR.5: (1) Erase/Blank check error\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	if (dsr & DSR_PROGRAM_STATUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		pr_notice("DSR.4: (1) Program Error\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	if (dsr & DSR_VPPS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		pr_notice("DSR.3: (1) Vpp low detect, operation aborted\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	if (dsr & DSR_PSS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		pr_notice("DSR.2: (1) Program suspended\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	if (dsr & DSR_DPS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 		pr_notice("DSR.1: (1) Aborted Erase/Program attempt on locked block\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static int wait_for_ready(struct map_info *map, struct flchip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 		unsigned int chip_op_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	unsigned int timeo, reset_timeo, sleep_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	unsigned int dsr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	flstate_t chip_state = chip->state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	/* set our timeout to 8 times the expected delay */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	timeo = chip_op_time * 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	if (!timeo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		timeo = 500000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	reset_timeo = timeo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	sleep_time = chip_op_time / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 		dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		if (dsr & DSR_READY_STATUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		if (!timeo) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 			printk(KERN_ERR "%s: Flash timeout error state %d \n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 							map->name, chip_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 			ret = -ETIME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 		/* OK Still waiting. Drop the lock, wait a while and retry. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 		mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 		if (sleep_time >= 1000000/HZ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 			 * Half of the normal delay still remaining
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 			 * can be performed with a sleeping delay instead
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 			 * of busy waiting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 			msleep(sleep_time/1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 			timeo -= sleep_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 			sleep_time = 1000000/HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 			udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 			cond_resched();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 			timeo--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		while (chip->state != chip_state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 			/* Someone's suspended the operation: sleep */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 			DECLARE_WAITQUEUE(wait, current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 			set_current_state(TASK_UNINTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 			add_wait_queue(&chip->wq, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 			mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 			schedule();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 			remove_wait_queue(&chip->wq, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		if (chip->erase_suspended || chip->write_suspended)  {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 			/* Suspend has occurred while sleep: reset timeout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 			timeo = reset_timeo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 			chip->erase_suspended = chip->write_suspended = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	/* check status for errors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	if (dsr & DSR_ERR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		/* Clear DSR*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		map_write(map, CMD(~(DSR_ERR)), map->pfow_base + PFOW_DSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		printk(KERN_WARNING"%s: Bad status on wait: 0x%x \n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 				map->name, dsr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 		print_drs_error(dsr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		ret = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	chip->state = FL_READY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static int get_chip(struct map_info *map, struct flchip *chip, int mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	DECLARE_WAITQUEUE(wait, current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)  retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		&& chip->state != FL_SYNCING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		 * OK. We have possibility for contension on the write/erase
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		 * operations which are global to the real chip and not per
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 		 * partition.  So let's fight it over in the partition which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		 * currently has authority on the operation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 		 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 		 * The rules are as follows:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 		 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		 * - any write operation must own shared->writing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		 * - any erase operation must own _both_ shared->writing and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		 *   shared->erasing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 		 * - contension arbitration is handled in the owner's context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 		 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 		 * The 'shared' struct can be read and/or written only when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		 * its lock is taken.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 		struct flchip_shared *shared = chip->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 		struct flchip *contender;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 		mutex_lock(&shared->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 		contender = shared->writing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 		if (contender && contender != chip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 			 * The engine to perform desired operation on this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 			 * partition is already in use by someone else.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 			 * Let's fight over it in the context of the chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 			 * currently using it.  If it is possible to suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 			 * that other partition will do just that, otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 			 * it'll happily send us to sleep.  In any case, when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 			 * get_chip returns success we're clear to go ahead.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 			ret = mutex_trylock(&contender->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 			mutex_unlock(&shared->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 			if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 				goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 			mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 			ret = chip_ready(map, contender, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 			mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 			if (ret == -EAGAIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 				mutex_unlock(&contender->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 				goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 			if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 				mutex_unlock(&contender->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 				return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 			mutex_lock(&shared->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 			/* We should not own chip if it is already in FL_SYNCING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 			 * state. Put contender and retry. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 			if (chip->state == FL_SYNCING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 				put_chip(map, contender);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 				mutex_unlock(&contender->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 				goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 			mutex_unlock(&contender->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 		/* Check if we have suspended erase on this chip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 		   Must sleep in such a case. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		if (mode == FL_ERASING && shared->erasing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 		    && shared->erasing->oldstate == FL_ERASING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 			mutex_unlock(&shared->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 			set_current_state(TASK_UNINTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 			add_wait_queue(&chip->wq, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 			mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 			schedule();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 			remove_wait_queue(&chip->wq, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 			mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 			goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 		/* We now own it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 		shared->writing = chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		if (mode == FL_ERASING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 			shared->erasing = chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		mutex_unlock(&shared->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	ret = chip_ready(map, chip, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	if (ret == -EAGAIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 		goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static int chip_ready(struct map_info *map, struct flchip *chip, int mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	DECLARE_WAITQUEUE(wait, current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	/* Prevent setting state FL_SYNCING for chip in suspended state. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	if (FL_SYNCING == mode && FL_READY != chip->oldstate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 		goto sleep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	switch (chip->state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	case FL_READY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	case FL_JEDEC_QUERY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	case FL_ERASING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		if (!lpddr->qinfo->SuspEraseSupp ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 			!(mode == FL_READY || mode == FL_POINT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 			goto sleep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 		map_write(map, CMD(LPDDR_SUSPEND),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 			map->pfow_base + PFOW_PROGRAM_ERASE_SUSPEND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 		chip->oldstate = FL_ERASING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 		chip->state = FL_ERASE_SUSPENDING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 		ret = wait_for_ready(map, chip, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 			/* Oops. something got wrong. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 			/* Resume and pretend we weren't here.  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 			put_chip(map, chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 			printk(KERN_ERR "%s: suspend operation failed."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 					"State may be wrong \n", map->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 			return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 		chip->erase_suspended = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 		chip->state = FL_READY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 		/* Erase suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	case FL_POINT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 		/* Only if there's no operation suspended... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 		if (mode == FL_READY && chip->oldstate == FL_READY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 			return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) sleep:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 		set_current_state(TASK_UNINTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 		add_wait_queue(&chip->wq, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 		mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 		schedule();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 		remove_wait_queue(&chip->wq, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 		mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 		return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static void put_chip(struct map_info *map, struct flchip *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	if (chip->priv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 		struct flchip_shared *shared = chip->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 		mutex_lock(&shared->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 		if (shared->writing == chip && chip->oldstate == FL_READY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 			/* We own the ability to write, but we're done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 			shared->writing = shared->erasing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 			if (shared->writing && shared->writing != chip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 				/* give back the ownership */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 				struct flchip *loaner = shared->writing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 				mutex_lock(&loaner->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 				mutex_unlock(&shared->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 				mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 				put_chip(map, loaner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 				mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 				mutex_unlock(&loaner->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 				wake_up(&chip->wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 				return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 			shared->erasing = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 			shared->writing = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 		} else if (shared->erasing == chip && shared->writing != chip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 			 * We own the ability to erase without the ability
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 			 * to write, which means the erase was suspended
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 			 * and some other partition is currently writing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 			 * Don't let the switch below mess things up since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 			 * we don't have ownership to resume anything.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 			mutex_unlock(&shared->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 			wake_up(&chip->wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 		mutex_unlock(&shared->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	switch (chip->oldstate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	case FL_ERASING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 		map_write(map, CMD(LPDDR_RESUME),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 				map->pfow_base + PFOW_COMMAND_CODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 		map_write(map, CMD(LPDDR_START_EXECUTION),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 				map->pfow_base + PFOW_COMMAND_EXECUTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 		chip->oldstate = FL_READY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 		chip->state = FL_ERASING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	case FL_READY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 		printk(KERN_ERR "%s: put_chip() called with oldstate %d!\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 				map->name, chip->oldstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	wake_up(&chip->wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) static int do_write_buffer(struct map_info *map, struct flchip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 			unsigned long adr, const struct kvec **pvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 			unsigned long *pvec_seek, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	map_word datum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 	int ret, wbufsize, word_gap, words;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 	const struct kvec *vec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	unsigned long vec_seek;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 	unsigned long prog_buf_ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	wbufsize = 1 << lpddr->qinfo->BufSizeShift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 	mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	ret = get_chip(map, chip, FL_WRITING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 		mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	/* Figure out the number of words to write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	word_gap = (-adr & (map_bankwidth(map)-1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 	words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 	if (!word_gap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		words--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 		word_gap = map_bankwidth(map) - word_gap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 		adr -= word_gap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 		datum = map_word_ff(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 	/* Write data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	/* Get the program buffer offset from PFOW register data first*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 	prog_buf_ofs = map->pfow_base + CMDVAL(map_read(map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 				map->pfow_base + PFOW_PROGRAM_BUFFER_OFFSET));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	vec = *pvec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	vec_seek = *pvec_seek;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 		int n = map_bankwidth(map) - word_gap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 		if (n > vec->iov_len - vec_seek)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 			n = vec->iov_len - vec_seek;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 		if (n > len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 			n = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 		if (!word_gap && (len < map_bankwidth(map)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 			datum = map_word_ff(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 		datum = map_word_load_partial(map, datum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 				vec->iov_base + vec_seek, word_gap, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 		len -= n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 		word_gap += n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 		if (!len || word_gap == map_bankwidth(map)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 			map_write(map, datum, prog_buf_ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 			prog_buf_ofs += map_bankwidth(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 			word_gap = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 		vec_seek += n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 		if (vec_seek == vec->iov_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 			vec++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 			vec_seek = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	} while (len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	*pvec = vec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	*pvec_seek = vec_seek;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	/* GO GO GO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	send_pfow_command(map, LPDDR_BUFF_PROGRAM, adr, wbufsize, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	chip->state = FL_WRITING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->ProgBufferTime));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	if (ret)	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 		printk(KERN_WARNING"%s Buffer program error: %d at %lx; \n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 			map->name, ret, adr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)  out:	put_chip(map, chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) static int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	struct map_info *map = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 	int chipnum = adr >> lpddr->chipshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	struct flchip *chip = &lpddr->chips[chipnum];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 	mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 	ret = get_chip(map, chip, FL_ERASING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 		mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 	send_pfow_command(map, LPDDR_BLOCK_ERASE, adr, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	chip->state = FL_ERASING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 	ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->BlockEraseTime)*1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 		printk(KERN_WARNING"%s Erase block error %d at : %llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 			map->name, ret, adr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)  out:	put_chip(map, chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 			size_t *retlen, u_char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 	struct map_info *map = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 	int chipnum = adr >> lpddr->chipshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 	struct flchip *chip = &lpddr->chips[chipnum];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 	mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	ret = get_chip(map, chip, FL_READY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 		mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 	map_copy_from(map, buf, adr, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 	*retlen = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	put_chip(map, chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 	mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 			size_t *retlen, void **mtdbuf, resource_size_t *phys)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	struct map_info *map = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	int chipnum = adr >> lpddr->chipshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 	unsigned long ofs, last_end = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	struct flchip *chip = &lpddr->chips[chipnum];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 	if (!map->virt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	/* ofs: offset within the first chip that the first read should start */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 	ofs = adr - (chipnum << lpddr->chipshift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 	*mtdbuf = (void *)map->virt + chip->start + ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	while (len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 		unsigned long thislen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 		if (chipnum >= lpddr->numchips)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 		/* We cannot point across chips that are virtually disjoint */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 		if (!last_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 			last_end = chip->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 		else if (chip->start != last_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 		if ((len + ofs - 1) >> lpddr->chipshift)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 			thislen = (1<<lpddr->chipshift) - ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 			thislen = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 		/* get the chip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 		mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 		ret = get_chip(map, chip, FL_POINT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 		mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 		chip->state = FL_POINT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 		chip->ref_point_counter++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 		*retlen += thislen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 		len -= thislen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 		ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 		last_end += 1 << lpddr->chipshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 		chipnum++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 		chip = &lpddr->chips[chipnum];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) static int lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 	struct map_info *map = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 	int chipnum = adr >> lpddr->chipshift, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 	unsigned long ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 	/* ofs: offset within the first chip that the first read should start */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 	ofs = adr - (chipnum << lpddr->chipshift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 	while (len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 		unsigned long thislen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 		struct flchip *chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 		chip = &lpddr->chips[chipnum];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 		if (chipnum >= lpddr->numchips)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 		if ((len + ofs - 1) >> lpddr->chipshift)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 			thislen = (1<<lpddr->chipshift) - ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 			thislen = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 		mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 		if (chip->state == FL_POINT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 			chip->ref_point_counter--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 			if (chip->ref_point_counter == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 				chip->state = FL_READY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 			printk(KERN_WARNING "%s: Warning: unpoint called on non"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 					"pointed region\n", map->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 			err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 		put_chip(map, chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 		mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 		len -= thislen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 		ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 		chipnum++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 				size_t *retlen, const u_char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 	struct kvec vec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) 	vec.iov_base = (void *) buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) 	vec.iov_len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) 	return lpddr_writev(mtd, &vec, 1, to, retlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 				unsigned long count, loff_t to, size_t *retlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 	struct map_info *map = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 	int chipnum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 	unsigned long ofs, vec_seek, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 	int wbufsize = 1 << lpddr->qinfo->BufSizeShift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 	size_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 	for (i = 0; i < count; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 		len += vecs[i].iov_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 	if (!len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 	chipnum = to >> lpddr->chipshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 	ofs = to;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 	vec_seek = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 		/* We must not cross write block boundaries */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 		int size = wbufsize - (ofs & (wbufsize-1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 		if (size > len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 			size = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 		ret = do_write_buffer(map, &lpddr->chips[chipnum],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 					  ofs, &vecs, &vec_seek, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 		ofs += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 		(*retlen) += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 		len -= size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 		/* Be nice and reschedule with the chip in a usable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 		 * state for other processes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 		cond_resched();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 	} while (len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 	unsigned long ofs, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 	struct map_info *map = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 	int size = 1 << lpddr->qinfo->UniformBlockSizeShift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 	ofs = instr->addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 	len = instr->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 	while (len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 		ret = do_erase_oneblock(mtd, ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 		ofs += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 		len -= size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) #define DO_XXLOCK_LOCK		1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) #define DO_XXLOCK_UNLOCK	2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) static int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 	struct map_info *map = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 	struct lpddr_private *lpddr = map->fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 	int chipnum = adr >> lpddr->chipshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 	struct flchip *chip = &lpddr->chips[chipnum];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 	mutex_lock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 	ret = get_chip(map, chip, FL_LOCKING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 		mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 	if (thunk == DO_XXLOCK_LOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 		send_pfow_command(map, LPDDR_LOCK_BLOCK, adr, adr + len, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 		chip->state = FL_LOCKING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 	} else if (thunk == DO_XXLOCK_UNLOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 		send_pfow_command(map, LPDDR_UNLOCK_BLOCK, adr, adr + len, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 		chip->state = FL_UNLOCKING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) 		BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) 	ret = wait_for_ready(map, chip, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) 	if (ret)	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) 		printk(KERN_ERR "%s: block unlock error status %d \n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 				map->name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) out:	put_chip(map, chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) 	mutex_unlock(&chip->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) 	return do_xxlock(mtd, ofs, len, DO_XXLOCK_LOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) 	return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) MODULE_DESCRIPTION("MTD driver for LPDDR flash chips");