Introducción a los controladores MTD /CFI para sistemas Linux

  

Algunos chips Intel FLASH (como la serie StrataFlash) admiten varias particiones, es decir, cada partición puede funcionar simultáneamente. Hay que decir que esta es una buena característica, pero también traerá algunos problemas.

Recuerde que cuando transplanté Linux-2.4.21 y colgué el sistema de archivos JFFS2, a menudo informé de algunos errores como "No se encontró la máscara de bits mágica". Seguí y descubrí que FLASH leyó algunos 0x80 y similares. Los datos, ver los datos encontrados que el FLASH tiene las características de la partición, y el controlador FLASH de Linux solo usa una variable de estado para indicar el estado del FLASH completo, lo que provocará el estado real de una partición determinada y el registro del sistema no coincide, lo que da como resultado la lectura del FLASH Este punto no está realmente en el estado de lectura.

La solución en ese momento era que, cada vez que lee, independientemente del estado del registro, puede ingresar primero al estado de lectura, por supuesto, esto provocará una disminución en el rendimiento. ¿Cuántos ciclos de reloj se pierden? .

En la era de Linux-2.6.x (específicamente 2.6.13), excepto Bloquear /Desbloquear (Linux no se desbloquea primero al borrar /escribir, la solución es inicializar todo Desbloquear primero) Además del problema anterior, incluso el error de partición múltiple no apareció. Me sorprendió decidir estudiar el controlador MTD /FLASH de Linux.

Antes de conducir, primero borre varios puntos de programación:

1: Lea y escriba, lea y escriba según el ancho del bus, tenga en cuenta que el ancho del chip FLASH no lo es (por ejemplo, espalda con espalda).

2: el direccionamiento, la dirección a la que debe acceder el programa y el valor obtenido por el pin de la dirección del chip FLASH son diferentes, por ejemplo, un chip FLASH de 16 bits. Para la CPU, 0x00 y 0x01 indican 2 bytes diferentes. Pero el pin FLASH obtiene 0, lo que significa que apunta a la primera PALABRA de FLASH. Se puede considerar que el bit0 del bus de dirección se deja flotando, o que se considera el bus de conversión, y el bit1 se genera en el bit0. Esto explica el punto 1.

3: El chip manual menciona que el desplazamiento se basa en WORD, y el ancho de bits de WORD depende del ancho de bits del chip, por lo que en el siguiente comando, offset real = manual offset * buswidth /8 .

4: La longitud de la variable mencionada en el manual del chip (por lo general, la información de CFI), por ejemplo, 2 significa que la variable es un número de 16 bits, pero al leer, debe leer 2 PALABRAS, luego poner cada PALABRA Los 8 bits inferiores se combinan en un número de 16 bits. Leer WORD y parchear juntos es realmente molesto, especialmente cuando se leen estructuras grandes, pero la función cfi_read_pri de cfi_util.c es simple.

5: Back-to-back, es decir, por ejemplo, dos chips de 16 bits están conectados a un bus de 32 bits. Lo que trae es el problema del direccionamiento. Obviamente, primero lea y escriba en 32 bits; en segundo lugar, la dirección del siguiente comando, el desplazamiento real = desplazamiento manual * intercalación * device_type /8, device_type = buswidth /interleave, y buswidth El tiempo es 32 (ancho del bus). Además, cuando está de espaldas, el código de estado del comando y el retorno es "doble", por ejemplo, dos de 16 bits consecutivos, el comando de lectura es 0x00ff00ff.

Si no desea escribir código que sea tan flexible como Linux (considerando varias conexiones /ancho de bit /información de adquisición de CFI, etc.), entonces las cosas son mucho más simples, solo considere el punto 1 y el tamaño del bloque de borrado. Por supuesto, si se trata de una conexión back-to-back, el tamaño real del bloque de borrado debe multiplicarse por una intercalación.

Ingresando el código de Linux

La relación entre CHIP /MAP /MTD aún es confusa, por lo que la siguiente es solo una breve descripción del contexto y varios puntos de programación.

1: construya la estructura map_info, especifique la dirección base /ancho de bit /tamaño y otra información, así como el límite "cfi_probe", luego llame a do_map_probe ().

2: do_map_probe () encuentra el controlador de chip "cfi_probe.c" según el nombre "cfi_probe" y llama a cfi_probe () directamente.

3: cfi_probe () llama directamente a mtd_do_chip_probe (), pasando el puntero a la función cfi_probe_chip ().

4: mtd_do_chip_probe () se divide en 2 pasos. Primero, se llama a genprobe_ident_chips () para detectar la información del chip, y luego se llama a check_cmd_set () para adquirir e inicializar el conjunto de comandos del chip (la inicialización de varias particiones está en él).

5: función genprobe_ident_chips () Si no considera la concatenación de múltiples chips, entonces mire la llamada genprobe_new_chip () anterior, luego de completar cfi.chipshift = cfi.cfiq- > DevSize, 2 ^ chipshift = Tamaño del flash.

6: genprobe_new_chip () enumera varios anchos de bits de chip y números consecutivos. En combinación con los ajustes de configuración, llame a cfi_probe_chip () en el paso 3, preste atención a cfi-> device_type = bankwidth /nr_chips, bankwidth is Ancho del bus, device_type es el ancho del chip. Aquí solo debemos prestar atención a la complejidad finita, la llamada complejidad finita se refiere a la conexión compleja determinada en el momento de la compilación. Por lo tanto, cfi_probe_chip () solo tiene éxito para la primera llamada. Si se inserta el FLASH de 32 bits de ancho en el bus de 16 bits, la segunda llamada tiene éxito.

7: cfi_probe_chip (), debido a la razón del paso 6, la función regresa directamente en cfi_chip_setup (), y no se considera el siguiente código.

8: cfi_chip_setup () lee información CFI, puede prestar atención a cómo Linux logra el punto 4.

9: regrese a la etapa check_cmd_set () del paso 4, ingrese la función cfi_cmdset_0001 (), primero llame a read_pri_intelext () para leer la información de extensión de Intel, y luego llame a cfi_intelext_setup () para inicializar su estructura.

10: función read_pri_intelext (), puede prestar atención a cómo leer la estructura de longitud variable, que es el uso de "need_more". Estos son los significados de las siguientes variables. Por ejemplo, para el tipo de chip FLASH StrataFlash 128Mb Bottom, la estructura de bloque es 4 * 32KB + 127 * 128KB = 16MB, un total de 16 particiones, 1MB por partición. Nb_parts = 2.

◆ Parte 1

NumIdentPartitions = 1 //Hay 1 particiones duplicadas

NumBlockTypes = 2 //Hay 2 tipos de Bloques diferentes en el área secundaria

Tipo 1

NumIdentBlocks = 3 //Hay 4 Bloques (3 + 1)

BlockSize = 0x80 //32KB (0x80 * 256)

2 tipo

NumIdentBlocks = 6 //Hay 7 Bloques (6 + 1)

BlockSize = 0x200 //128KB (0x200 * 256)

◆ Parte 2 < Br>

NumIdentPartitions = 15 //Hay 15 particiones duplicadas

NumBlockTypes = 1 //Hay 1 tipo de Bloque en la partición

Tipo 1

NumIdentBlocks = 7 //Hay 8 Bloques (7 + 1)

BlockSize = 0x200 //128KB (0x200 * 256)

11: La función cfi_intelext_setup () primero crea la información mtd_erase_region_info de acuerdo con el CFI, luego Llame a cfi_intelext_partition_fixup () para admitir la partición.

12: cfi_intelext_partition_fixup () se utiliza para crear un chip virtual. Cada partición corresponde a un chip, pero no está completamente establecida según la información de la extensión CFI. En cambio, se supone que cada partición tiene el mismo tamaño. Cfi- > chipshift se ajusta a partshift, y cada chip virtual - inicio se ajusta a la dirección base de cada partición. En el futuro, la función de entrada cfi_varsize_frob () para acceder a FLASH obtendrá chipnum (chipnum = ofs > > cfi- > chipshift) según ofs, por lo que se supone que las particiones son consistentes.

Copyright © Conocimiento de Windows All Rights Reserved