18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright © 2009 - Maxim Levitsky
48c2ecf20Sopenharmony_ci * Common routines & support for SmartMedia/xD format
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include <linux/bitops.h>
78c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci/* Full oob structure as written on the flash */
108c2ecf20Sopenharmony_cistruct sm_oob {
118c2ecf20Sopenharmony_ci	uint32_t reserved;
128c2ecf20Sopenharmony_ci	uint8_t data_status;
138c2ecf20Sopenharmony_ci	uint8_t block_status;
148c2ecf20Sopenharmony_ci	uint8_t lba_copy1[2];
158c2ecf20Sopenharmony_ci	uint8_t ecc2[3];
168c2ecf20Sopenharmony_ci	uint8_t lba_copy2[2];
178c2ecf20Sopenharmony_ci	uint8_t ecc1[3];
188c2ecf20Sopenharmony_ci} __packed;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* one sector is always 512 bytes, but it can consist of two nand pages */
228c2ecf20Sopenharmony_ci#define SM_SECTOR_SIZE		512
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* oob area is also 16 bytes, but might be from two pages */
258c2ecf20Sopenharmony_ci#define SM_OOB_SIZE		16
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* This is maximum zone size, and all devices that have more that one zone
288c2ecf20Sopenharmony_ci   have this size */
298c2ecf20Sopenharmony_ci#define SM_MAX_ZONE_SIZE 	1024
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* support for small page nand */
328c2ecf20Sopenharmony_ci#define SM_SMALL_PAGE 		256
338c2ecf20Sopenharmony_ci#define SM_SMALL_OOB_SIZE	8
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciint sm_register_device(struct mtd_info *mtd, int smartmedia);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic inline int sm_sector_valid(struct sm_oob *oob)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	return hweight16(oob->data_status) >= 5;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline int sm_block_valid(struct sm_oob *oob)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	return hweight16(oob->block_status) >= 7;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline int sm_block_erased(struct sm_oob *oob)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	static const uint32_t erased_pattern[4] = {
528c2ecf20Sopenharmony_ci		0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* First test for erased block */
558c2ecf20Sopenharmony_ci	if (!memcmp(oob, erased_pattern, sizeof(*oob)))
568c2ecf20Sopenharmony_ci		return 1;
578c2ecf20Sopenharmony_ci	return 0;
588c2ecf20Sopenharmony_ci}
59