Ejemplo n.º 1
0
/*
 * cfi_chip_query - detect a CFI chip
 *
 * fill in the struct cfi as we discover what's there
 */
static bool
cfi_chip_query(struct cfi * const cfi)
{
	const bus_size_t cfi_query_offset[] = {
		CFI_QUERY_MODE_ADDR,
		CFI_QUERY_MODE_ALT_ADDR
	};

	KASSERT(cfi != NULL);
	KASSERT(cfi->cfi_bst != NULL);

	for (int j=0; j < __arraycount(cfi_query_offset); j++) {

		cfi_reset_default(cfi);
		cfi_cmd(cfi, cfi_query_offset[j], CFI_QUERY_DATA);

		if (cfi_read_qry(cfi, 0x10) == 'Q' &&
		    cfi_read_qry(cfi, 0x11) == 'R' &&
		    cfi_read_qry(cfi, 0x12) == 'Y') {
			switch(cfi->cfi_portwidth) {
			case 0:
				cfi_chip_query_1(cfi);
				break;
			case 1:
				cfi_chip_query_2(cfi);
				break;
			case 2:
				cfi_chip_query_4(cfi);
				break;
			case 3:
				cfi_chip_query_8(cfi);
				break;
			default:
				panic("%s: bad portwidth %d\n",
				    __func__, cfi->cfi_portwidth);
			}

			switch (cfi->cfi_qry_data.id_pri) {
			case 0x0002:
				cfi->cfi_unlock_addr1 = CFI_AMD_UNLOCK_ADDR1;
				cfi->cfi_unlock_addr2 = CFI_AMD_UNLOCK_ADDR2;
				break;
			default:
				DPRINTF(("%s: unsupported CFI cmdset %#04x\n",
				    __func__, cfi->cfi_qry_data.id_pri));
				return false;
			}

			cfi->cfi_emulated = false;
			return true;
		}
	}

	return false;
}
Ejemplo n.º 2
0
static int
cfi_devioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
    struct thread *td)
{
	struct cfi_softc *sc;
	struct cfiocqry *rq;
	int error;
	u_char val;

	sc = dev->si_drv1;
	error = 0;

	switch (cmd) {
	case CFIOCQRY:
		if (sc->sc_writing) {
			error = cfi_block_finish(sc);
			if (error)
				break;
		}
		rq = (struct cfiocqry *)data;
		if (rq->offset >= sc->sc_size / sc->sc_width)
			return (ESPIPE);
		if (rq->offset + rq->count > sc->sc_size / sc->sc_width)
			return (ENOSPC);

		while (!error && rq->count--) {
			val = cfi_read_qry(sc, rq->offset++);
			error = copyout(&val, rq->buffer++, 1);
		}
		break;
#ifdef CFI_SUPPORT_STRATAFLASH
	case CFIOCGFACTORYPR:
		error = cfi_intel_get_factory_pr(sc, (uint64_t *)data);
		break;
	case CFIOCGOEMPR:
		error = cfi_intel_get_oem_pr(sc, (uint64_t *)data);
		break;
	case CFIOCSOEMPR:
		error = cfi_intel_set_oem_pr(sc, *(uint64_t *)data);
		break;
	case CFIOCGPLR:
		error = cfi_intel_get_plr(sc, (uint32_t *)data);
		break;
	case CFIOCSPLR:
		error = cfi_intel_set_plr(sc);
		break;
#endif /* CFI_SUPPORT_STRATAFLASH */
	default:
		error = ENOIOCTL;
		break;
	}
	return (error);
}
Ejemplo n.º 3
0
int
cfi_attach(device_t dev) 
{
	struct cfi_softc *sc;
	u_int blksz, blocks;
	u_int r, u;

	sc = device_get_softc(dev);
	sc->sc_dev = dev;

	sc->sc_rid = 0;
	sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
	    RF_ACTIVE);
	if (sc->sc_res == NULL)
		return (ENXIO);

	sc->sc_tag = rman_get_bustag(sc->sc_res);
	sc->sc_handle = rman_get_bushandle(sc->sc_res);

	/* Get time-out values for erase and write. */
	sc->sc_write_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_WRITE);
	sc->sc_erase_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_ERASE);
	sc->sc_write_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_WRITE);
	sc->sc_erase_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_ERASE);

	/* Get erase regions. */
	sc->sc_regions = cfi_read_qry(sc, CFI_QRY_NREGIONS);
	sc->sc_region = malloc(sc->sc_regions * sizeof(struct cfi_region),
	    M_TEMP, M_WAITOK | M_ZERO);
	for (r = 0; r < sc->sc_regions; r++) {
		blocks = cfi_read_qry(sc, CFI_QRY_REGION(r)) |
		    (cfi_read_qry(sc, CFI_QRY_REGION(r) + 1) << 8);
		sc->sc_region[r].r_blocks = blocks + 1;

		blksz = cfi_read_qry(sc, CFI_QRY_REGION(r) + 2) |
		    (cfi_read_qry(sc, CFI_QRY_REGION(r) + 3) << 8);
		sc->sc_region[r].r_blksz = (blksz == 0) ? 128 :
		    blksz * 256;
	}

	/* Reset the device to a default state. */
	cfi_write(sc, 0, CFI_BCS_CLEAR_STATUS);

	if (bootverbose) {
		device_printf(dev, "[");
		for (r = 0; r < sc->sc_regions; r++) {
			printf("%ux%s%s", sc->sc_region[r].r_blocks,
			    cfi_fmtsize(sc->sc_region[r].r_blksz),
			    (r == sc->sc_regions - 1) ? "]\n" : ",");
		}
	}

	u = device_get_unit(dev);
	sc->sc_nod = make_dev(&cfi_cdevsw, u, UID_ROOT, GID_WHEEL, 0600,
	    "%s%u", cfi_driver_name, u);
	sc->sc_nod->si_drv1 = sc;

	device_add_child(dev, "cfid", -1);
	bus_generic_attach(dev);

	return (0);
}
Ejemplo n.º 4
0
int
cfi_probe(device_t dev)
{
	char desc[80];
	struct cfi_softc *sc;
	char *vend_str;
	int error;
	uint16_t iface, vend;

	sc = device_get_softc(dev);
	sc->sc_dev = dev;

	sc->sc_rid = 0;
	sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
	    RF_ACTIVE);
	if (sc->sc_res == NULL)
		return (ENXIO);

	sc->sc_tag = rman_get_bustag(sc->sc_res);
	sc->sc_handle = rman_get_bushandle(sc->sc_res);

	if (sc->sc_width == 0) {
		sc->sc_width = 1;
		while (sc->sc_width <= 4) {
			if (cfi_read_qry(sc, CFI_QRY_IDENT) == 'Q')
				break;
			sc->sc_width <<= 1;
		}
	} else if (cfi_read_qry(sc, CFI_QRY_IDENT) != 'Q') {
		error = ENXIO;
		goto out;
	}
	if (sc->sc_width > 4) {
		error = ENXIO;
		goto out;
	}

	/* We got a Q. Check if we also have the R and the Y. */
	if (cfi_read_qry(sc, CFI_QRY_IDENT + 1) != 'R' ||
	    cfi_read_qry(sc, CFI_QRY_IDENT + 2) != 'Y') {
		error = ENXIO;
		goto out;
	}

	/* Get the vendor and command set. */
	vend = cfi_read_qry(sc, CFI_QRY_VEND) |
	    (cfi_read_qry(sc, CFI_QRY_VEND + 1) << 8);

	sc->sc_cmdset = vend;

	switch (vend) {
	case CFI_VEND_AMD_ECS:
	case CFI_VEND_AMD_SCS:
		vend_str = "AMD/Fujitsu";
		break;
	case CFI_VEND_INTEL_ECS:
		vend_str = "Intel/Sharp";
		break;
	case CFI_VEND_INTEL_SCS:
		vend_str = "Intel";
		break;
	case CFI_VEND_MITSUBISHI_ECS:
	case CFI_VEND_MITSUBISHI_SCS:
		vend_str = "Mitsubishi";
		break;
	default:
		vend_str = "Unknown vendor";
		break;
	}

	/* Get the device size. */
	sc->sc_size = 1U << cfi_read_qry(sc, CFI_QRY_SIZE);

	/* Sanity-check the I/F */
	iface = cfi_read_qry(sc, CFI_QRY_IFACE) |
	    (cfi_read_qry(sc, CFI_QRY_IFACE + 1) << 8);

	/*
	 * Adding 1 to iface will give us a bit-wise "switch"
	 * that allows us to test for the interface width by
	 * testing a single bit.
	 */
	iface++;

	error = (iface & sc->sc_width) ? 0 : EINVAL;
	if (error)
		goto out;

	snprintf(desc, sizeof(desc), "%s - %s", vend_str,
	    cfi_fmtsize(sc->sc_size));
	device_set_desc_copy(dev, desc);

 out:
	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
	return (error);
}