162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2016-2017 Micron Technology, Inc.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Authors:
662306a36Sopenharmony_ci *	Peter Pan <peterpandong@micron.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/mtd/spinand.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define SPINAND_MFR_MICRON		0x2c
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define MICRON_STATUS_ECC_MASK		GENMASK(6, 4)
1662306a36Sopenharmony_ci#define MICRON_STATUS_ECC_NO_BITFLIPS	(0 << 4)
1762306a36Sopenharmony_ci#define MICRON_STATUS_ECC_1TO3_BITFLIPS	(1 << 4)
1862306a36Sopenharmony_ci#define MICRON_STATUS_ECC_4TO6_BITFLIPS	(3 << 4)
1962306a36Sopenharmony_ci#define MICRON_STATUS_ECC_7TO8_BITFLIPS	(5 << 4)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define MICRON_CFG_CR			BIT(0)
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * As per datasheet, die selection is done by the 6th bit of Die
2562306a36Sopenharmony_ci * Select Register (Address 0xD0).
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci#define MICRON_DIE_SELECT_REG	0xD0
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define MICRON_SELECT_DIE(x)	((x) << 6)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic SPINAND_OP_VARIANTS(quadio_read_cache_variants,
3262306a36Sopenharmony_ci		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
3362306a36Sopenharmony_ci		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
3462306a36Sopenharmony_ci		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
3562306a36Sopenharmony_ci		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
3662306a36Sopenharmony_ci		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
3762306a36Sopenharmony_ci		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic SPINAND_OP_VARIANTS(x4_write_cache_variants,
4062306a36Sopenharmony_ci		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
4162306a36Sopenharmony_ci		SPINAND_PROG_LOAD(true, 0, NULL, 0));
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic SPINAND_OP_VARIANTS(x4_update_cache_variants,
4462306a36Sopenharmony_ci		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
4562306a36Sopenharmony_ci		SPINAND_PROG_LOAD(false, 0, NULL, 0));
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* Micron  MT29F2G01AAAED Device */
4862306a36Sopenharmony_cistatic SPINAND_OP_VARIANTS(x4_read_cache_variants,
4962306a36Sopenharmony_ci			   SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
5062306a36Sopenharmony_ci			   SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
5162306a36Sopenharmony_ci			   SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
5262306a36Sopenharmony_ci			   SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic SPINAND_OP_VARIANTS(x1_write_cache_variants,
5562306a36Sopenharmony_ci			   SPINAND_PROG_LOAD(true, 0, NULL, 0));
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic SPINAND_OP_VARIANTS(x1_update_cache_variants,
5862306a36Sopenharmony_ci			   SPINAND_PROG_LOAD(false, 0, NULL, 0));
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
6162306a36Sopenharmony_ci				  struct mtd_oob_region *region)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	if (section)
6462306a36Sopenharmony_ci		return -ERANGE;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	region->offset = mtd->oobsize / 2;
6762306a36Sopenharmony_ci	region->length = mtd->oobsize / 2;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return 0;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
7362306a36Sopenharmony_ci				   struct mtd_oob_region *region)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	if (section)
7662306a36Sopenharmony_ci		return -ERANGE;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* Reserve 2 bytes for the BBM. */
7962306a36Sopenharmony_ci	region->offset = 2;
8062306a36Sopenharmony_ci	region->length = (mtd->oobsize / 2) - 2;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic const struct mtd_ooblayout_ops micron_8_ooblayout = {
8662306a36Sopenharmony_ci	.ecc = micron_8_ooblayout_ecc,
8762306a36Sopenharmony_ci	.free = micron_8_ooblayout_free,
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,
9162306a36Sopenharmony_ci				  struct mtd_oob_region *region)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct spinand_device *spinand = mtd_to_spinand(mtd);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (section >= spinand->base.memorg.pagesize /
9662306a36Sopenharmony_ci			mtd->ecc_step_size)
9762306a36Sopenharmony_ci		return -ERANGE;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	region->offset = (section * 16) + 8;
10062306a36Sopenharmony_ci	region->length = 8;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return 0;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic int micron_4_ooblayout_free(struct mtd_info *mtd, int section,
10662306a36Sopenharmony_ci				   struct mtd_oob_region *region)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	struct spinand_device *spinand = mtd_to_spinand(mtd);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (section >= spinand->base.memorg.pagesize /
11162306a36Sopenharmony_ci			mtd->ecc_step_size)
11262306a36Sopenharmony_ci		return -ERANGE;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (section) {
11562306a36Sopenharmony_ci		region->offset = 16 * section;
11662306a36Sopenharmony_ci		region->length = 8;
11762306a36Sopenharmony_ci	} else {
11862306a36Sopenharmony_ci		/* section 0 has two bytes reserved for the BBM */
11962306a36Sopenharmony_ci		region->offset = 2;
12062306a36Sopenharmony_ci		region->length = 6;
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return 0;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic const struct mtd_ooblayout_ops micron_4_ooblayout = {
12762306a36Sopenharmony_ci	.ecc = micron_4_ooblayout_ecc,
12862306a36Sopenharmony_ci	.free = micron_4_ooblayout_free,
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic int micron_select_target(struct spinand_device *spinand,
13262306a36Sopenharmony_ci				unsigned int target)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG,
13562306a36Sopenharmony_ci						      spinand->scratchbuf);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (target > 1)
13862306a36Sopenharmony_ci		return -EINVAL;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	*spinand->scratchbuf = MICRON_SELECT_DIE(target);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	return spi_mem_exec_op(spinand->spimem, &op);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int micron_8_ecc_get_status(struct spinand_device *spinand,
14662306a36Sopenharmony_ci				   u8 status)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	switch (status & MICRON_STATUS_ECC_MASK) {
14962306a36Sopenharmony_ci	case STATUS_ECC_NO_BITFLIPS:
15062306a36Sopenharmony_ci		return 0;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	case STATUS_ECC_UNCOR_ERROR:
15362306a36Sopenharmony_ci		return -EBADMSG;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	case MICRON_STATUS_ECC_1TO3_BITFLIPS:
15662306a36Sopenharmony_ci		return 3;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	case MICRON_STATUS_ECC_4TO6_BITFLIPS:
15962306a36Sopenharmony_ci		return 6;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	case MICRON_STATUS_ECC_7TO8_BITFLIPS:
16262306a36Sopenharmony_ci		return 8;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	default:
16562306a36Sopenharmony_ci		break;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return -EINVAL;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic const struct spinand_info micron_spinand_table[] = {
17262306a36Sopenharmony_ci	/* M79A 2Gb 3.3V */
17362306a36Sopenharmony_ci	SPINAND_INFO("MT29F2G01ABAGD",
17462306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
17562306a36Sopenharmony_ci		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
17662306a36Sopenharmony_ci		     NAND_ECCREQ(8, 512),
17762306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
17862306a36Sopenharmony_ci					      &x4_write_cache_variants,
17962306a36Sopenharmony_ci					      &x4_update_cache_variants),
18062306a36Sopenharmony_ci		     0,
18162306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_8_ooblayout,
18262306a36Sopenharmony_ci				     micron_8_ecc_get_status)),
18362306a36Sopenharmony_ci	/* M79A 2Gb 1.8V */
18462306a36Sopenharmony_ci	SPINAND_INFO("MT29F2G01ABBGD",
18562306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
18662306a36Sopenharmony_ci		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
18762306a36Sopenharmony_ci		     NAND_ECCREQ(8, 512),
18862306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
18962306a36Sopenharmony_ci					      &x4_write_cache_variants,
19062306a36Sopenharmony_ci					      &x4_update_cache_variants),
19162306a36Sopenharmony_ci		     0,
19262306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_8_ooblayout,
19362306a36Sopenharmony_ci				     micron_8_ecc_get_status)),
19462306a36Sopenharmony_ci	/* M78A 1Gb 3.3V */
19562306a36Sopenharmony_ci	SPINAND_INFO("MT29F1G01ABAFD",
19662306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
19762306a36Sopenharmony_ci		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
19862306a36Sopenharmony_ci		     NAND_ECCREQ(8, 512),
19962306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
20062306a36Sopenharmony_ci					      &x4_write_cache_variants,
20162306a36Sopenharmony_ci					      &x4_update_cache_variants),
20262306a36Sopenharmony_ci		     0,
20362306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_8_ooblayout,
20462306a36Sopenharmony_ci				     micron_8_ecc_get_status)),
20562306a36Sopenharmony_ci	/* M78A 1Gb 1.8V */
20662306a36Sopenharmony_ci	SPINAND_INFO("MT29F1G01ABAFD",
20762306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
20862306a36Sopenharmony_ci		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
20962306a36Sopenharmony_ci		     NAND_ECCREQ(8, 512),
21062306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
21162306a36Sopenharmony_ci					      &x4_write_cache_variants,
21262306a36Sopenharmony_ci					      &x4_update_cache_variants),
21362306a36Sopenharmony_ci		     0,
21462306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_8_ooblayout,
21562306a36Sopenharmony_ci				     micron_8_ecc_get_status)),
21662306a36Sopenharmony_ci	/* M79A 4Gb 3.3V */
21762306a36Sopenharmony_ci	SPINAND_INFO("MT29F4G01ADAGD",
21862306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
21962306a36Sopenharmony_ci		     NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
22062306a36Sopenharmony_ci		     NAND_ECCREQ(8, 512),
22162306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
22262306a36Sopenharmony_ci					      &x4_write_cache_variants,
22362306a36Sopenharmony_ci					      &x4_update_cache_variants),
22462306a36Sopenharmony_ci		     0,
22562306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_8_ooblayout,
22662306a36Sopenharmony_ci				     micron_8_ecc_get_status),
22762306a36Sopenharmony_ci		     SPINAND_SELECT_TARGET(micron_select_target)),
22862306a36Sopenharmony_ci	/* M70A 4Gb 3.3V */
22962306a36Sopenharmony_ci	SPINAND_INFO("MT29F4G01ABAFD",
23062306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
23162306a36Sopenharmony_ci		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
23262306a36Sopenharmony_ci		     NAND_ECCREQ(8, 512),
23362306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
23462306a36Sopenharmony_ci					      &x4_write_cache_variants,
23562306a36Sopenharmony_ci					      &x4_update_cache_variants),
23662306a36Sopenharmony_ci		     SPINAND_HAS_CR_FEAT_BIT,
23762306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_8_ooblayout,
23862306a36Sopenharmony_ci				     micron_8_ecc_get_status)),
23962306a36Sopenharmony_ci	/* M70A 4Gb 1.8V */
24062306a36Sopenharmony_ci	SPINAND_INFO("MT29F4G01ABBFD",
24162306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
24262306a36Sopenharmony_ci		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
24362306a36Sopenharmony_ci		     NAND_ECCREQ(8, 512),
24462306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
24562306a36Sopenharmony_ci					      &x4_write_cache_variants,
24662306a36Sopenharmony_ci					      &x4_update_cache_variants),
24762306a36Sopenharmony_ci		     SPINAND_HAS_CR_FEAT_BIT,
24862306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_8_ooblayout,
24962306a36Sopenharmony_ci				     micron_8_ecc_get_status)),
25062306a36Sopenharmony_ci	/* M70A 8Gb 3.3V */
25162306a36Sopenharmony_ci	SPINAND_INFO("MT29F8G01ADAFD",
25262306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
25362306a36Sopenharmony_ci		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
25462306a36Sopenharmony_ci		     NAND_ECCREQ(8, 512),
25562306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
25662306a36Sopenharmony_ci					      &x4_write_cache_variants,
25762306a36Sopenharmony_ci					      &x4_update_cache_variants),
25862306a36Sopenharmony_ci		     SPINAND_HAS_CR_FEAT_BIT,
25962306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_8_ooblayout,
26062306a36Sopenharmony_ci				     micron_8_ecc_get_status),
26162306a36Sopenharmony_ci		     SPINAND_SELECT_TARGET(micron_select_target)),
26262306a36Sopenharmony_ci	/* M70A 8Gb 1.8V */
26362306a36Sopenharmony_ci	SPINAND_INFO("MT29F8G01ADBFD",
26462306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
26562306a36Sopenharmony_ci		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
26662306a36Sopenharmony_ci		     NAND_ECCREQ(8, 512),
26762306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
26862306a36Sopenharmony_ci					      &x4_write_cache_variants,
26962306a36Sopenharmony_ci					      &x4_update_cache_variants),
27062306a36Sopenharmony_ci		     SPINAND_HAS_CR_FEAT_BIT,
27162306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_8_ooblayout,
27262306a36Sopenharmony_ci				     micron_8_ecc_get_status),
27362306a36Sopenharmony_ci		     SPINAND_SELECT_TARGET(micron_select_target)),
27462306a36Sopenharmony_ci	/* M69A 2Gb 3.3V */
27562306a36Sopenharmony_ci	SPINAND_INFO("MT29F2G01AAAED",
27662306a36Sopenharmony_ci		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),
27762306a36Sopenharmony_ci		     NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),
27862306a36Sopenharmony_ci		     NAND_ECCREQ(4, 512),
27962306a36Sopenharmony_ci		     SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,
28062306a36Sopenharmony_ci					      &x1_write_cache_variants,
28162306a36Sopenharmony_ci					      &x1_update_cache_variants),
28262306a36Sopenharmony_ci		     0,
28362306a36Sopenharmony_ci		     SPINAND_ECCINFO(&micron_4_ooblayout, NULL)),
28462306a36Sopenharmony_ci};
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic int micron_spinand_init(struct spinand_device *spinand)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	/*
28962306a36Sopenharmony_ci	 * M70A device series enable Continuous Read feature at Power-up,
29062306a36Sopenharmony_ci	 * which is not supported. Disable this bit to avoid any possible
29162306a36Sopenharmony_ci	 * failure.
29262306a36Sopenharmony_ci	 */
29362306a36Sopenharmony_ci	if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT)
29462306a36Sopenharmony_ci		return spinand_upd_cfg(spinand, MICRON_CFG_CR, 0);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return 0;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
30062306a36Sopenharmony_ci	.init = micron_spinand_init,
30162306a36Sopenharmony_ci};
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ciconst struct spinand_manufacturer micron_spinand_manufacturer = {
30462306a36Sopenharmony_ci	.id = SPINAND_MFR_MICRON,
30562306a36Sopenharmony_ci	.name = "Micron",
30662306a36Sopenharmony_ci	.chips = micron_spinand_table,
30762306a36Sopenharmony_ci	.nchips = ARRAY_SIZE(micron_spinand_table),
30862306a36Sopenharmony_ci	.ops = &micron_spinand_manuf_ops,
30962306a36Sopenharmony_ci};
310