|
@@ -1,37 +1,34 @@
|
|
-From 1077f225d9906c04dd56b93e63900701beb92483 Mon Sep 17 00:00:00 2001
|
|
|
|
|
|
+From 72f3df2ae3d841447cba8188d48b90d91325b284 Mon Sep 17 00:00:00 2001
|
|
From: zfdx123 <[email protected]>
|
|
From: zfdx123 <[email protected]>
|
|
-Date: Thu, 26 Jan 2023 09:42:50 +0800
|
|
|
|
|
|
+Date: Thu, 26 Jan 2023 12:49:13 +0800
|
|
Subject: [PATCH] ramips: MT7620 add Support HiWiFi R33(C312B B52)
|
|
Subject: [PATCH] ramips: MT7620 add Support HiWiFi R33(C312B B52)
|
|
|
|
|
|
---
|
|
---
|
|
- .../generic/files/drivers/net/phy/rtl8367b.c | 11 +
|
|
|
|
- .../linux/ramips/dts/mt7620a_hiwifi_r33.dts | 235 ++
|
|
|
|
- target/linux/ramips/image/mt7620.mk | 21 +
|
|
|
|
- .../mt7620/base-files/etc/board.d/01_leds | 3 +
|
|
|
|
- .../mt7620/base-files/etc/board.d/02_network | 13 +
|
|
|
|
- .../etc/hotplug.d/ieee80211/10_fix_wifi_mac | 7 +
|
|
|
|
- .../mt7620/base-files/lib/upgrade/platform.sh | 3 +
|
|
|
|
- target/linux/ramips/mt7620/config-5.10 | 21 +
|
|
|
|
- target/linux/ramips/mt7620/target.mk | 2 +-
|
|
|
|
- ...38-mtd-ralink-add-mt7620-nand-driver.patch | 2373 +++++++++++++++++
|
|
|
|
- 10 files changed, 2688 insertions(+), 1 deletion(-)
|
|
|
|
|
|
+ .../generic/files/drivers/net/phy/rtl8367b.c | 9 +
|
|
|
|
+ .../linux/ramips/dts/mt7620a_hiwifi_r33.dts | 235 ++++++++++++++++++
|
|
|
|
+ target/linux/ramips/image/mt7620.mk | 22 ++
|
|
|
|
+ .../mt7620/base-files/etc/board.d/01_leds | 3 +
|
|
|
|
+ .../mt7620/base-files/etc/board.d/02_network | 13 +
|
|
|
|
+ .../etc/hotplug.d/ieee80211/10_fix_wifi_mac | 33 +++
|
|
|
|
+ .../mt7620/base-files/lib/upgrade/platform.sh | 3 +
|
|
|
|
+ 7 files changed, 318 insertions(+)
|
|
create mode 100644 target/linux/ramips/dts/mt7620a_hiwifi_r33.dts
|
|
create mode 100644 target/linux/ramips/dts/mt7620a_hiwifi_r33.dts
|
|
- create mode 100644 target/linux/ramips/patches-5.10/0038-mtd-ralink-add-mt7620-nand-driver.patch
|
|
|
|
|
|
+ create mode 100644 target/linux/ramips/mt7620/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac
|
|
|
|
|
|
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/target/linux/generic/files/drivers/net/phy/rtl8367b.c
|
|
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/target/linux/generic/files/drivers/net/phy/rtl8367b.c
|
|
-index 3599791a517bb..942cbd73b7205 100644
|
|
|
|
|
|
+index 3599791a517b..6297e07628ba 100644
|
|
--- a/target/linux/generic/files/drivers/net/phy/rtl8367b.c
|
|
--- a/target/linux/generic/files/drivers/net/phy/rtl8367b.c
|
|
+++ b/target/linux/generic/files/drivers/net/phy/rtl8367b.c
|
|
+++ b/target/linux/generic/files/drivers/net/phy/rtl8367b.c
|
|
-@@ -266,6 +266,8 @@ struct rtl8367b_initval {
|
|
|
|
- #define RTL8367B_MIB_RXB_ID 0 /* IfInOctets */
|
|
|
|
- #define RTL8367B_MIB_TXB_ID 28 /* IfOutOctets */
|
|
|
|
|
|
+@@ -263,6 +263,8 @@ struct rtl8367b_initval {
|
|
|
|
+ u16 val;
|
|
|
|
+ };
|
|
|
|
|
|
+u32 rtl_device_id;
|
|
+u32 rtl_device_id;
|
|
+
|
|
+
|
|
- static struct rtl8366_mib_counter
|
|
|
|
- rtl8367b_mib_counters[RTL8367B_NUM_MIB_COUNTERS] = {
|
|
|
|
- {0, 0, 4, "ifInOctets" },
|
|
|
|
-@@ -612,8 +614,14 @@ static int rtl8367b_write_initvals(struct rtl8366_smi *smi,
|
|
|
|
|
|
+ #define RTL8367B_MIB_RXB_ID 0 /* IfInOctets */
|
|
|
|
+ #define RTL8367B_MIB_TXB_ID 28 /* IfOutOctets */
|
|
|
|
+
|
|
|
|
+@@ -612,6 +614,10 @@ static int rtl8367b_write_initvals(struct rtl8366_smi *smi,
|
|
int err;
|
|
int err;
|
|
int i;
|
|
int i;
|
|
|
|
|
|
@@ -40,13 +37,9 @@ index 3599791a517bb..942cbd73b7205 100644
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
for (i = 0; i < count; i++)
|
|
for (i = 0; i < count; i++)
|
|
-+ {
|
|
|
|
REG_WR(smi, initvals[i].reg, initvals[i].val);
|
|
REG_WR(smi, initvals[i].reg, initvals[i].val);
|
|
-+ }
|
|
|
|
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-@@ -1540,7 +1548,10 @@ static int rtl8367b_detect(struct rtl8366_smi *smi)
|
|
|
|
|
|
+@@ -1540,7 +1546,10 @@ static int rtl8367b_detect(struct rtl8366_smi *smi)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -59,10 +52,10 @@ index 3599791a517bb..942cbd73b7205 100644
|
|
break;
|
|
break;
|
|
diff --git a/target/linux/ramips/dts/mt7620a_hiwifi_r33.dts b/target/linux/ramips/dts/mt7620a_hiwifi_r33.dts
|
|
diff --git a/target/linux/ramips/dts/mt7620a_hiwifi_r33.dts b/target/linux/ramips/dts/mt7620a_hiwifi_r33.dts
|
|
new file mode 100644
|
|
new file mode 100644
|
|
-index 0000000000000..09f5a84b773c5
|
|
|
|
|
|
+index 000000000000..6761b1b68a06
|
|
--- /dev/null
|
|
--- /dev/null
|
|
+++ b/target/linux/ramips/dts/mt7620a_hiwifi_r33.dts
|
|
+++ b/target/linux/ramips/dts/mt7620a_hiwifi_r33.dts
|
|
-@@ -0,0 +1,235 @@
|
|
|
|
|
|
+@@ -0,0 +1,234 @@
|
|
+#include "mt7620a.dtsi"
|
|
+#include "mt7620a.dtsi"
|
|
+
|
|
+
|
|
+#include <dt-bindings/gpio/gpio.h>
|
|
+#include <dt-bindings/gpio/gpio.h>
|
|
@@ -122,7 +115,7 @@ index 0000000000000..09f5a84b773c5
|
|
+ reg = <0x540000 0x1c80000>;
|
|
+ reg = <0x540000 0x1c80000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+
|
|
-+ partition@21c0000 {
|
|
|
|
|
|
++ bdinfo: partition@21c0000 {
|
|
+ label = "bdinfo";
|
|
+ label = "bdinfo";
|
|
+ reg = <0x21c0000 0x80000>;
|
|
+ reg = <0x21c0000 0x80000>;
|
|
+ read-only;
|
|
+ read-only;
|
|
@@ -130,7 +123,7 @@ index 0000000000000..09f5a84b773c5
|
|
+
|
|
+
|
|
+ ubiconcat1: partition@2240000 {
|
|
+ ubiconcat1: partition@2240000 {
|
|
+ label = "ubiconcat1";
|
|
+ label = "ubiconcat1";
|
|
-+ reg = <0x2240000 0x5d40000>;
|
|
|
|
|
|
++ reg = <0x2240000 0x5dc0000>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
@@ -146,7 +139,7 @@ index 0000000000000..09f5a84b773c5
|
|
+
|
|
+
|
|
+ partition@0 {
|
|
+ partition@0 {
|
|
+ label = "ubi";
|
|
+ label = "ubi";
|
|
-+ reg = <0x0 0x79c0000>;
|
|
|
|
|
|
++ reg = <0x0 0x7a40000>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
@@ -162,12 +155,13 @@ index 0000000000000..09f5a84b773c5
|
|
+
|
|
+
|
|
+ led_system: system {
|
|
+ led_system: system {
|
|
+ label = "blue:system";
|
|
+ label = "blue:system";
|
|
-+ gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
|
|
|
|
|
|
++ gpios = <&gpio0 9 GPIO_ACTIVE_LOW>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+
|
|
+ turbo {
|
|
+ turbo {
|
|
+ label = "blue:turbo";
|
|
+ label = "blue:turbo";
|
|
-+ gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>;
|
|
|
|
|
|
++ gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
|
|
|
|
++ linux,default-trigger = "none";
|
|
+ };
|
|
+ };
|
|
+
|
|
+
|
|
+ wlan2g {
|
|
+ wlan2g {
|
|
@@ -211,13 +205,6 @@ index 0000000000000..09f5a84b773c5
|
|
+ };
|
|
+ };
|
|
+};
|
|
+};
|
|
+
|
|
+
|
|
-+//在最新的openwrt master分支中sysc已经被剔除,此处进行备份标记
|
|
|
|
-+// &sysc {
|
|
|
|
-+// ralink,gpiomux = "i2c", "jtag";
|
|
|
|
-+// ralink,uartmux = "gpio";
|
|
|
|
-+// ralink,wdtmux = <1>;
|
|
|
|
-+// };
|
|
|
|
-+
|
|
|
|
+&gpio3 {
|
|
+&gpio3 {
|
|
+ status = "okay";
|
|
+ status = "okay";
|
|
+};
|
|
+};
|
|
@@ -234,14 +221,17 @@ index 0000000000000..09f5a84b773c5
|
|
+ status = "okay";
|
|
+ status = "okay";
|
|
+};
|
|
+};
|
|
+
|
|
+
|
|
|
|
++&gsw {
|
|
|
|
++ mediatek,port4-gmac;
|
|
|
|
++ mediatek,ephy-base = /bits/ 8 <12>;
|
|
|
|
++};
|
|
|
|
++
|
|
+ðernet {
|
|
+ðernet {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&rgmii1_pins &rgmii2_pins &mdio_pins>;
|
|
+ pinctrl-0 = <&rgmii1_pins &rgmii2_pins &mdio_pins>;
|
|
+
|
|
+
|
|
-+ //mtd-mac-address = <&factory 0x4>;
|
|
|
|
-+
|
|
|
|
-+ nvmem-cells = <&macaddr_factory_4>;
|
|
|
|
-+ nvmem-cell-names = "mac-address";
|
|
|
|
|
|
++ nvmem-cells = <&macaddr_bdinfo_18a>;
|
|
|
|
++ nvmem-cell-names = "mac-address-ascii";
|
|
+
|
|
+
|
|
+ port@5 {
|
|
+ port@5 {
|
|
+ status = "okay";
|
|
+ status = "okay";
|
|
@@ -260,26 +250,28 @@ index 0000000000000..09f5a84b773c5
|
|
+ };
|
|
+ };
|
|
+};
|
|
+};
|
|
+
|
|
+
|
|
-+//5G WIFI
|
|
|
|
|
|
++&wmac {
|
|
|
|
++ pinctrl-names = "default", "pa_gpio";
|
|
|
|
++ pinctrl-0 = <&pa_pins>;
|
|
|
|
++ pinctrl-1 = <&pa_gpio_pins>;
|
|
|
|
++ ralink,mtd-eeprom = <&factory 0x0>;
|
|
|
|
++
|
|
|
|
++ nvmem-cells = <&macaddr_bdinfo_18a>;
|
|
|
|
++ nvmem-cell-names = "mac-address-ascii";
|
|
|
|
++ mac-address-increment = <1>;
|
|
|
|
++};
|
|
|
|
++
|
|
+&pcie0 {
|
|
+&pcie0 {
|
|
+ wifi@0,0 {
|
|
+ wifi@0,0 {
|
|
+ compatible = "pci14c3,7662";
|
|
+ compatible = "pci14c3,7662";
|
|
+ reg = <0x0000 0 0 0 0>;
|
|
+ reg = <0x0000 0 0 0 0>;
|
|
+ mediatek,mtd-eeprom = <&factory 0x8000>;
|
|
+ mediatek,mtd-eeprom = <&factory 0x8000>;
|
|
+ ieee80211-freq-limit = <5000000 6000000>;
|
|
+ ieee80211-freq-limit = <5000000 6000000>;
|
|
-+ // nvmem-cells = <&macaddr_factory_4>;
|
|
|
|
-+ // nvmem-cell-names = "mac-address";
|
|
|
|
-+ // mac-address-increment = <2>;
|
|
|
|
-+ };
|
|
|
|
-+};
|
|
|
|
+
|
|
+
|
|
-+//2.4G WIFI
|
|
|
|
-+&wmac {
|
|
|
|
-+ pinctrl-names = "default";
|
|
|
|
-+ pinctrl-0 = <&pa_pins>;
|
|
|
|
-+ ralink,mtd-eeprom = <&factory 0x0>;
|
|
|
|
-+ // nvmem-cells = <&macaddr_factory_4>;
|
|
|
|
-+ // nvmem-cell-names = "mac-address";
|
|
|
|
|
|
++ nvmem-cells = <&macaddr_bdinfo_18a>;
|
|
|
|
++ nvmem-cell-names = "mac-address-ascii";
|
|
|
|
++ mac-address-increment = <2>;
|
|
|
|
++ };
|
|
+};
|
|
+};
|
|
+
|
|
+
|
|
+&state_default {
|
|
+&state_default {
|
|
@@ -289,28 +281,29 @@ index 0000000000000..09f5a84b773c5
|
|
+ };
|
|
+ };
|
|
+};
|
|
+};
|
|
+
|
|
+
|
|
-+&factory {
|
|
|
|
-+ compatible = "nvmem-cells";
|
|
|
|
-+ #address-cells = <1>;
|
|
|
|
-+ #size-cells = <1>;
|
|
|
|
|
|
++&bdinfo {
|
|
|
|
++ compatible = "nvmem-cells";
|
|
|
|
++ #address-cells = <1>;
|
|
|
|
++ #size-cells = <1>;
|
|
+
|
|
+
|
|
-+ macaddr_factory_4: macaddr@4 {
|
|
|
|
-+ reg = <0x4 0x6>;
|
|
|
|
-+ };
|
|
|
|
|
|
++ macaddr_bdinfo_18a: macaddr@18a {
|
|
|
|
++ reg = <0x18a 0x11>;
|
|
|
|
++ };
|
|
+};
|
|
+};
|
|
diff --git a/target/linux/ramips/image/mt7620.mk b/target/linux/ramips/image/mt7620.mk
|
|
diff --git a/target/linux/ramips/image/mt7620.mk b/target/linux/ramips/image/mt7620.mk
|
|
-index 445d3dec34238..c90b8d1f93d02 100644
|
|
|
|
|
|
+index 631e5043f411..c68b9a69c60d 100644
|
|
--- a/target/linux/ramips/image/mt7620.mk
|
|
--- a/target/linux/ramips/image/mt7620.mk
|
|
+++ b/target/linux/ramips/image/mt7620.mk
|
|
+++ b/target/linux/ramips/image/mt7620.mk
|
|
-@@ -1495,3 +1495,24 @@ define Device/zyxel_keenetic-viva
|
|
|
|
|
|
+@@ -1338,3 +1338,25 @@ define Device/zyxel_keenetic-viva
|
|
SUPPORTED_DEVICES += kng_rc
|
|
SUPPORTED_DEVICES += kng_rc
|
|
endef
|
|
endef
|
|
TARGET_DEVICES += zyxel_keenetic-viva
|
|
TARGET_DEVICES += zyxel_keenetic-viva
|
|
+
|
|
+
|
|
|
|
++
|
|
+define Device/hiwifi_r33
|
|
+define Device/hiwifi_r33
|
|
+ SOC := mt7620a
|
|
+ SOC := mt7620a
|
|
+ DEVICE_VENDOR := HiWiFi
|
|
+ DEVICE_VENDOR := HiWiFi
|
|
-+ DEVICE_MODEL := R33 / 3Pro
|
|
|
|
|
|
++ DEVICE_MODEL := R33
|
|
+ DEVICE_PACKAGES := kmod-usb2 kmod-usb-ohci kmod-usb-ledtrig-usbport \
|
|
+ DEVICE_PACKAGES := kmod-usb2 kmod-usb-ohci kmod-usb-ledtrig-usbport \
|
|
+ kmod-switch-rtl8366-smi kmod-switch-rtl8367b kmod-mt76x2
|
|
+ kmod-switch-rtl8366-smi kmod-switch-rtl8367b kmod-mt76x2
|
|
+ BLOCKSIZE := 128k
|
|
+ BLOCKSIZE := 128k
|
|
@@ -327,25 +320,26 @@ index 445d3dec34238..c90b8d1f93d02 100644
|
|
+ SUPPORTED_DEVICES += r33
|
|
+ SUPPORTED_DEVICES += r33
|
|
+endef
|
|
+endef
|
|
+TARGET_DEVICES += hiwifi_r33
|
|
+TARGET_DEVICES += hiwifi_r33
|
|
|
|
+\ No newline at end of file
|
|
diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds
|
|
diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds
|
|
-index 36e3045a38a82..5e221159eb80a 100644
|
|
|
|
|
|
+index 53487d752688..1240b0efdae4 100644
|
|
--- a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds
|
|
--- a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds
|
|
+++ b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds
|
|
+++ b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds
|
|
-@@ -126,6 +126,9 @@ hiwifi,hc5761)
|
|
|
|
|
|
+@@ -112,6 +112,9 @@ hiwifi,hc5761)
|
|
hiwifi,hc5861)
|
|
hiwifi,hc5861)
|
|
ucidef_set_led_switch "internet" "internet" "blue:internet" "switch0" "0x20"
|
|
ucidef_set_led_switch "internet" "internet" "blue:internet" "switch0" "0x20"
|
|
;;
|
|
;;
|
|
+hiwifi,r33)
|
|
+hiwifi,r33)
|
|
-+ ucidef_set_led_netdev "internet" "internet" "blue:internet" "eth0.2" "link tx rx"
|
|
|
|
|
|
++ ucidef_set_led_switch "internet" "internet" "blue:internet" "switch1" "0x01"
|
|
+ ;;
|
|
+ ;;
|
|
hnet,c108)
|
|
hnet,c108)
|
|
ucidef_set_led_netdev "lan" "lan" "green:lan" "eth0"
|
|
ucidef_set_led_netdev "lan" "lan" "green:lan" "eth0"
|
|
ucidef_set_led_netdev "modem" "modem" "green:modem" "wwan0"
|
|
ucidef_set_led_netdev "modem" "modem" "green:modem" "wwan0"
|
|
diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network
|
|
diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network
|
|
-index 424e3709969a1..cbba6c2029366 100644
|
|
|
|
|
|
+index 00ffb1b5420c..5f4e7268e8a9 100644
|
|
--- a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network
|
|
--- a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network
|
|
+++ b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network
|
|
+++ b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network
|
|
-@@ -175,6 +175,13 @@ ramips_setup_interfaces()
|
|
|
|
|
|
+@@ -156,6 +156,13 @@ ramips_setup_interfaces()
|
|
ucidef_add_switch "switch0" \
|
|
ucidef_add_switch "switch0" \
|
|
"0:lan" "1:lan" "5:wan" "6@eth0"
|
|
"0:lan" "1:lan" "5:wan" "6@eth0"
|
|
;;
|
|
;;
|
|
@@ -359,7 +353,7 @@ index 424e3709969a1..cbba6c2029366 100644
|
|
iodata,wn-ac1167gr|\
|
|
iodata,wn-ac1167gr|\
|
|
iodata,wn-ac733gr3|\
|
|
iodata,wn-ac733gr3|\
|
|
iptime,a1004ns)
|
|
iptime,a1004ns)
|
|
-@@ -350,6 +357,12 @@ ramips_setup_macs()
|
|
|
|
|
|
+@@ -336,6 +343,12 @@ ramips_setup_macs()
|
|
[ -n "$lan_mac" ] || lan_mac=$(cat /sys/class/net/eth0/address)
|
|
[ -n "$lan_mac" ] || lan_mac=$(cat /sys/class/net/eth0/address)
|
|
wan_mac=$(macaddr_add "$lan_mac" 1)
|
|
wan_mac=$(macaddr_add "$lan_mac" 1)
|
|
;;
|
|
;;
|
|
@@ -389,12 +383,12 @@ index aa0ad99158271..c7b818a0af7c0 100644
|
|
+ ;;
|
|
+ ;;
|
|
esac
|
|
esac
|
|
diff --git a/target/linux/ramips/mt7620/base-files/lib/upgrade/platform.sh b/target/linux/ramips/mt7620/base-files/lib/upgrade/platform.sh
|
|
diff --git a/target/linux/ramips/mt7620/base-files/lib/upgrade/platform.sh b/target/linux/ramips/mt7620/base-files/lib/upgrade/platform.sh
|
|
-index 9f71dc918e50a..9c1aa42326e82 100755
|
|
|
|
|
|
+index 40272d4a744d..e4f83fd8ccb5 100755
|
|
--- a/target/linux/ramips/mt7620/base-files/lib/upgrade/platform.sh
|
|
--- a/target/linux/ramips/mt7620/base-files/lib/upgrade/platform.sh
|
|
+++ b/target/linux/ramips/mt7620/base-files/lib/upgrade/platform.sh
|
|
+++ b/target/linux/ramips/mt7620/base-files/lib/upgrade/platform.sh
|
|
-@@ -30,6 +30,9 @@ platform_do_upgrade() {
|
|
|
|
- }
|
|
|
|
- default_do_upgrade "$1"
|
|
|
|
|
|
+@@ -35,6 +35,9 @@ platform_do_upgrade() {
|
|
|
|
+ dd if=/dev/mtd0 bs=64 count=1 2>/dev/null | grep -qi breed && CI_KERNPART_EXT="kernel_stock"
|
|
|
|
+ nand_do_upgrade "$1"
|
|
;;
|
|
;;
|
|
+ hiwifi,r33)
|
|
+ hiwifi,r33)
|
|
+ nand_do_upgrade "$1"
|
|
+ nand_do_upgrade "$1"
|
|
@@ -402,2473 +396,3 @@ index 9f71dc918e50a..9c1aa42326e82 100755
|
|
*)
|
|
*)
|
|
default_do_upgrade "$1"
|
|
default_do_upgrade "$1"
|
|
;;
|
|
;;
|
|
-diff --git a/target/linux/ramips/mt7620/config-5.10 b/target/linux/ramips/mt7620/config-5.10
|
|
|
|
-index 135c1689e164d..c2c06b9996b45 100644
|
|
|
|
---- a/target/linux/ramips/mt7620/config-5.10
|
|
|
|
-+++ b/target/linux/ramips/mt7620/config-5.10
|
|
|
|
-@@ -32,7 +32,13 @@ CONFIG_CPU_SUPPORTS_HIGHMEM=y
|
|
|
|
- CONFIG_CPU_SUPPORTS_MSA=y
|
|
|
|
- CONFIG_CRYPTO_BLAKE2S=y
|
|
|
|
- CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
|
|
|
|
-+CONFIG_CRC16=y
|
|
|
|
-+CONFIG_CRYPTO_DEFLATE=y
|
|
|
|
-+CONFIG_CRYPTO_GF128MUL=y
|
|
|
|
-+CONFIG_CRYPTO_HASH_INFO=y
|
|
|
|
- CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
|
|
|
|
-+CONFIG_CRYPTO_LZO=y
|
|
|
|
-+CONFIG_CRYPTO_NULL2=y
|
|
|
|
- CONFIG_CRYPTO_RNG2=y
|
|
|
|
- CONFIG_CSRC_R4K=y
|
|
|
|
- CONFIG_DEBUG_PINCTRL=y
|
|
|
|
-@@ -88,9 +94,12 @@ CONFIG_IRQ_WORK=y
|
|
|
|
- # CONFIG_KERNEL_ZSTD is not set
|
|
|
|
- CONFIG_LIBFDT=y
|
|
|
|
- CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
|
|
|
-+CONFIG_LZO_COMPRESS=y
|
|
|
|
-+CONFIG_LZO_DECOMPRESS=y
|
|
|
|
- CONFIG_MARVELL_PHY=y
|
|
|
|
- CONFIG_MDIO_BUS=y
|
|
|
|
- CONFIG_MDIO_DEVICE=y
|
|
|
|
-+CONFIG_MDIO_DEVRES=y
|
|
|
|
- CONFIG_MEMFD_CREATE=y
|
|
|
|
- CONFIG_MFD_SYSCON=y
|
|
|
|
- CONFIG_MIGRATION=y
|
|
|
|
-@@ -103,6 +112,7 @@ CONFIG_MIPS_CLOCK_VSYSCALL=y
|
|
|
|
- # CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
|
|
|
|
- # CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
|
|
|
|
- CONFIG_MIPS_CMDLINE_FROM_DTB=y
|
|
|
|
-+CONFIG_MIPS_EBPF_JIT=y
|
|
|
|
- # CONFIG_MIPS_ELF_APPENDED_DTB is not set
|
|
|
|
- CONFIG_MIPS_L1_CACHE_SHIFT=5
|
|
|
|
- CONFIG_MIPS_LD_CAN_LINK_VDSO=y
|
|
|
|
-@@ -113,6 +123,7 @@ CONFIG_MODULES_USE_ELF_REL=y
|
|
|
|
- # CONFIG_MT7621_WDT is not set
|
|
|
|
- # CONFIG_MTD_CFI_INTELEXT is not set
|
|
|
|
- CONFIG_MTD_CMDLINE_PARTS=y
|
|
|
|
-+CONFIG_MTD_NAND_MT7620=y
|
|
|
|
- # CONFIG_MTD_PARSER_TPLINK_SAFELOADER is not set
|
|
|
|
- CONFIG_MTD_PHYSMAP=y
|
|
|
|
- CONFIG_MTD_SPI_NOR=y
|
|
|
|
-@@ -122,6 +133,10 @@ CONFIG_MTD_SPLIT_JIMAGE_FW=y
|
|
|
|
- CONFIG_MTD_SPLIT_SEAMA_FW=y
|
|
|
|
- CONFIG_MTD_SPLIT_TPLINK_FW=y
|
|
|
|
- CONFIG_MTD_SPLIT_UIMAGE_FW=y
|
|
|
|
-+CONFIG_MTD_UBI=y
|
|
|
|
-+CONFIG_MTD_UBI_BEB_LIMIT=20
|
|
|
|
-+CONFIG_MTD_UBI_BLOCK=y
|
|
|
|
-+CONFIG_MTD_UBI_WL_THRESHOLD=4096
|
|
|
|
- CONFIG_MTD_VIRT_CONCAT=y
|
|
|
|
- CONFIG_NEED_DMA_MAP_STATE=y
|
|
|
|
- CONFIG_NEED_PER_CPU_KM=y
|
|
|
|
-@@ -165,6 +180,7 @@ CONFIG_RESET_CONTROLLER=y
|
|
|
|
- CONFIG_SERIAL_8250_RT288X=y
|
|
|
|
- CONFIG_SERIAL_MCTRL_GPIO=y
|
|
|
|
- CONFIG_SERIAL_OF_PLATFORM=y
|
|
|
|
-+CONFIG_SGL_ALLOC=y
|
|
|
|
- CONFIG_SOC_MT7620=y
|
|
|
|
- # CONFIG_SOC_MT7621 is not set
|
|
|
|
- # CONFIG_SOC_RT288X is not set
|
|
|
|
-@@ -193,6 +209,11 @@ CONFIG_TICK_CPU_ACCOUNTING=y
|
|
|
|
- CONFIG_TIMER_OF=y
|
|
|
|
- CONFIG_TIMER_PROBE=y
|
|
|
|
- CONFIG_TINY_SRCU=y
|
|
|
|
-+CONFIG_UBIFS_FS=y
|
|
|
|
-+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
|
|
|
|
-+# CONFIG_UBIFS_FS_ZSTD is not set
|
|
|
|
- CONFIG_USB_SUPPORT=y
|
|
|
|
- CONFIG_USE_OF=y
|
|
|
|
- CONFIG_WATCHDOG_CORE=y
|
|
|
|
-+CONFIG_ZLIB_DEFLATE=y
|
|
|
|
-+CONFIG_ZLIB_INFLATE=y
|
|
|
|
-diff --git a/target/linux/ramips/mt7620/target.mk b/target/linux/ramips/mt7620/target.mk
|
|
|
|
-index 5fc61e49cf8f3..ce992fc208b68 100644
|
|
|
|
---- a/target/linux/ramips/mt7620/target.mk
|
|
|
|
-+++ b/target/linux/ramips/mt7620/target.mk
|
|
|
|
-@@ -4,7 +4,7 @@
|
|
|
|
-
|
|
|
|
- SUBTARGET:=mt7620
|
|
|
|
- BOARDNAME:=MT7620 based boards
|
|
|
|
--FEATURES+=usb ramdisk
|
|
|
|
-+FEATURES+=usb nand ramdisk
|
|
|
|
- CPU_TYPE:=24kc
|
|
|
|
-
|
|
|
|
- DEFAULT_PACKAGES += kmod-rt2800-soc wpad-basic-wolfssl swconfig
|
|
|
|
-diff --git a/target/linux/ramips/patches-5.10/0038-mtd-ralink-add-mt7620-nand-driver.patch b/target/linux/ramips/patches-5.10/0038-mtd-ralink-add-mt7620-nand-driver.patch
|
|
|
|
-new file mode 100644
|
|
|
|
-index 0000000000000..b2d098b048319
|
|
|
|
---- /dev/null
|
|
|
|
-+++ b/target/linux/ramips/patches-5.10/0038-mtd-ralink-add-mt7620-nand-driver.patch
|
|
|
|
-@@ -0,0 +1,2373 @@
|
|
|
|
-+From afb07a5b467217af1df4162c707cbe554a79130d Mon Sep 17 00:00:00 2001
|
|
|
|
-+From: Chen Minqiang <[email protected]>
|
|
|
|
-+Date: Thu, 3 Sep 2020 03:27:48 +0800
|
|
|
|
-+Subject: [PATCH] mtd ralink add mt7620-nand driver
|
|
|
|
-+
|
|
|
|
-+---
|
|
|
|
-+ drivers/mtd/maps/Kconfig | 4 +
|
|
|
|
-+ drivers/mtd/maps/Makefile | 1 +
|
|
|
|
-+ drivers/mtd/maps/ralink_nand.c | 2095 ++++++++++++++++++++++++++++++++
|
|
|
|
-+ drivers/mtd/maps/ralink_nand.h | 240 ++++
|
|
|
|
-+ 4 files changed, 2340 insertions(+)
|
|
|
|
-+ create mode 100644 drivers/mtd/maps/ralink_nand.c
|
|
|
|
-+ create mode 100644 drivers/mtd/maps/ralink_nand.h
|
|
|
|
-+
|
|
|
|
-+--- a/drivers/mtd/maps/Kconfig
|
|
|
|
-++++ b/drivers/mtd/maps/Kconfig
|
|
|
|
-+@@ -423,4 +423,8 @@ config MTD_PISMO
|
|
|
|
-+
|
|
|
|
-+ When built as a module, it will be called pismo.ko
|
|
|
|
-+
|
|
|
|
-++config MTD_NAND_MT7620
|
|
|
|
-++ tristate "Support for NAND on Mediatek MT7620"
|
|
|
|
-++ depends on RALINK && SOC_MT7620
|
|
|
|
-++
|
|
|
|
-+ endmenu
|
|
|
|
-+--- a/drivers/mtd/maps/Makefile
|
|
|
|
-++++ b/drivers/mtd/maps/Makefile
|
|
|
|
-+@@ -46,3 +46,4 @@ obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_
|
|
|
|
-+ obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
|
|
|
|
-+ obj-$(CONFIG_MTD_VMU) += vmu-flash.o
|
|
|
|
-+ obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
|
|
|
|
-++obj-$(CONFIG_MTD_NAND_MT7620) += ralink_nand.o
|
|
|
|
-+--- /dev/null
|
|
|
|
-++++ b/drivers/mtd/maps/ralink_nand.c
|
|
|
|
-+@@ -0,0 +1,2095 @@
|
|
|
|
-++#define DEBUG
|
|
|
|
-++#include <linux/device.h>
|
|
|
|
-++#undef DEBUG
|
|
|
|
-++#include <linux/slab.h>
|
|
|
|
-++#include <linux/mtd/mtd.h>
|
|
|
|
-++#include <linux/delay.h>
|
|
|
|
-++#include <linux/module.h>
|
|
|
|
-++#include <linux/interrupt.h>
|
|
|
|
-++#include <linux/dma-mapping.h>
|
|
|
|
-++#include <linux/mtd/partitions.h>
|
|
|
|
-++#include <asm/io.h>
|
|
|
|
-++#include <linux/delay.h>
|
|
|
|
-++#include <linux/sched.h>
|
|
|
|
-++#include <linux/of.h>
|
|
|
|
-++#include <linux/platform_device.h>
|
|
|
|
-++
|
|
|
|
-++#include "ralink_nand.h"
|
|
|
|
-++#ifdef RANDOM_GEN_BAD_BLOCK
|
|
|
|
-++#include <linux/random.h>
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++#define LARGE_MTD_BOOT_PART_SIZE (CFG_BLOCKSIZE<<2)
|
|
|
|
-++#define LARGE_MTD_CONFIG_PART_SIZE (CFG_BLOCKSIZE<<2)
|
|
|
|
-++#define LARGE_MTD_FACTORY_PART_SIZE (CFG_BLOCKSIZE<<1)
|
|
|
|
-++
|
|
|
|
-++#define BLOCK_ALIGNED(a) ((a) & (CFG_BLOCKSIZE - 1))
|
|
|
|
-++
|
|
|
|
-++#define READ_STATUS_RETRY 1000
|
|
|
|
-++
|
|
|
|
-++struct nand_ecclayout {
|
|
|
|
-++ __u32 eccbytes;
|
|
|
|
-++ __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
|
|
|
|
-++ __u32 oobavail;
|
|
|
|
-++ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
|
|
|
|
-++};
|
|
|
|
-++
|
|
|
|
-++struct mtd_info *ranfc_mtd = NULL;
|
|
|
|
-++
|
|
|
|
-++int skipbbt = 0;
|
|
|
|
-++int ranfc_debug = 1;
|
|
|
|
-++static int ranfc_bbt = 1;
|
|
|
|
-++#if defined (WORKAROUND_RX_BUF_OV)
|
|
|
|
-++static int ranfc_verify = 1;
|
|
|
|
-++#endif
|
|
|
|
-++static u32 nand_addrlen;
|
|
|
|
-++
|
|
|
|
-++#if 0
|
|
|
|
-++module_param(ranfc_debug, int, 0644);
|
|
|
|
-++module_param(ranfc_bbt, int, 0644);
|
|
|
|
-++module_param(ranfc_verify, int, 0644);
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++#if 0
|
|
|
|
-++#define ra_dbg(args...) do { if (ranfc_debug) printk(args); } while(0)
|
|
|
|
-++#else
|
|
|
|
-++#define ra_dbg(args...)
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++#define CLEAR_INT_STATUS() ra_outl(NFC_INT_ST, ra_inl(NFC_INT_ST))
|
|
|
|
-++#define NFC_TRANS_DONE() (ra_inl(NFC_INT_ST) & INT_ST_ND_DONE)
|
|
|
|
-++
|
|
|
|
-++int is_nand_page_2048 = 0;
|
|
|
|
-++const unsigned int nand_size_map[2][3] = {{25, 30, 30}, {20, 27, 30}};
|
|
|
|
-++
|
|
|
|
-++static int nfc_wait_ready(int snooze_ms);
|
|
|
|
-++
|
|
|
|
-++static const char * const mtk_probe_types[] = { "cmdlinepart", "ofpart", NULL };
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * reset nand chip
|
|
|
|
-++ */
|
|
|
|
-++static int nfc_chip_reset(void)
|
|
|
|
-++{
|
|
|
|
-++ int status;
|
|
|
|
-++
|
|
|
|
-++ //ra_dbg("%s:\n", __func__);
|
|
|
|
-++
|
|
|
|
-++ // reset nand flash
|
|
|
|
-++ ra_outl(NFC_CMD1, 0x0);
|
|
|
|
-++ ra_outl(NFC_CMD2, 0xff);
|
|
|
|
-++ ra_outl(NFC_ADDR, 0x0);
|
|
|
|
-++ ra_outl(NFC_CONF, 0x0411);
|
|
|
|
-++
|
|
|
|
-++ status = nfc_wait_ready(5); //erase wait 5us
|
|
|
|
-++ if (status & NAND_STATUS_FAIL) {
|
|
|
|
-++ printk("%s: fail \n", __func__);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return (int)(status & NAND_STATUS_FAIL);
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * clear NFC and flash chip.
|
|
|
|
-++ */
|
|
|
|
-++static int nfc_all_reset(void)
|
|
|
|
-++{
|
|
|
|
-++ int retry;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: \n", __func__);
|
|
|
|
-++
|
|
|
|
-++ // reset controller
|
|
|
|
-++ ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x02); //clear data buffer
|
|
|
|
-++ ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) & ~0x02); //clear data buffer
|
|
|
|
-++
|
|
|
|
-++ CLEAR_INT_STATUS();
|
|
|
|
-++
|
|
|
|
-++ retry = READ_STATUS_RETRY;
|
|
|
|
-++ while ((ra_inl(NFC_INT_ST) & 0x02) != 0x02 && retry--);
|
|
|
|
-++ if (retry <= 0) {
|
|
|
|
-++ printk("nfc_all_reset: clean buffer fail \n");
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ retry = READ_STATUS_RETRY;
|
|
|
|
-++ while ((ra_inl(NFC_STATUS) & 0x1) != 0x0 && retry--) { //fixme, controller is busy ?
|
|
|
|
-++ udelay(1);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ nfc_chip_reset();
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/** NOTICE: only called by nfc_wait_ready().
|
|
|
|
-++ * @return -1, nfc can not get transction done
|
|
|
|
-++ * @return 0, ok.
|
|
|
|
-++ */
|
|
|
|
-++static int _nfc_read_status(char *status)
|
|
|
|
-++{
|
|
|
|
-++ unsigned long cmd1, conf;
|
|
|
|
-++ int int_st, nfc_st;
|
|
|
|
-++ int retry;
|
|
|
|
-++
|
|
|
|
-++ cmd1 = 0x70;
|
|
|
|
-++ conf = 0x000101 | (1 << 20);
|
|
|
|
-++
|
|
|
|
-++ //fixme, should we check nfc status?
|
|
|
|
-++ CLEAR_INT_STATUS();
|
|
|
|
-++
|
|
|
|
-++ ra_outl(NFC_CMD1, cmd1);
|
|
|
|
-++ ra_outl(NFC_CONF, conf);
|
|
|
|
-++
|
|
|
|
-++ /* FIXME,
|
|
|
|
-++ * 1. since we have no wired ready signal, directly
|
|
|
|
-++ * calling this function is not gurantee to read right status under ready state.
|
|
|
|
-++ * 2. the other side, we can not determine how long to become ready, this timeout retry is nonsense.
|
|
|
|
-++ * 3. SUGGESTION: call nfc_read_status() from nfc_wait_ready(),
|
|
|
|
-++ * that is aware about caller (in sementics) and has snooze plused nfc ND_DONE.
|
|
|
|
-++ */
|
|
|
|
-++ retry = READ_STATUS_RETRY;
|
|
|
|
-++ do {
|
|
|
|
-++ nfc_st = ra_inl(NFC_STATUS);
|
|
|
|
-++ int_st = ra_inl(NFC_INT_ST);
|
|
|
|
-++
|
|
|
|
-++ ndelay(10);
|
|
|
|
-++ } while (!(int_st & INT_ST_RX_BUF_RDY) && retry--);
|
|
|
|
-++
|
|
|
|
-++ if (!(int_st & INT_ST_RX_BUF_RDY)) {
|
|
|
|
-++ printk("nfc_read_status: NFC fail, int_st(%x), retry:%x. nfc:%x, reset nfc and flash. \n",
|
|
|
|
-++ int_st, retry, nfc_st);
|
|
|
|
-++ nfc_all_reset();
|
|
|
|
-++ *status = NAND_STATUS_FAIL;
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ *status = (char)(le32_to_cpu(ra_inl(NFC_DATA)) & 0x0ff);
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * @return !0, chip protect.
|
|
|
|
-++ * @return 0, chip not protected.
|
|
|
|
-++ */
|
|
|
|
-++static int nfc_check_wp(void)
|
|
|
|
-++{
|
|
|
|
-++ /* Check the WP bit */
|
|
|
|
-++#if !defined CONFIG_NOT_SUPPORT_WP
|
|
|
|
-++ return !!(ra_inl(NFC_CTRL) & 0x01);
|
|
|
|
-++#else
|
|
|
|
-++ char result = 0;
|
|
|
|
-++ int ret;
|
|
|
|
-++
|
|
|
|
-++ ret = _nfc_read_status(&result);
|
|
|
|
-++ //FIXME, if ret < 0
|
|
|
|
-++
|
|
|
|
-++ return !(result & NAND_STATUS_WP);
|
|
|
|
-++#endif
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++#if !defined CONFIG_NOT_SUPPORT_RB
|
|
|
|
-++/*
|
|
|
|
-++ * @return !0, chip ready.
|
|
|
|
-++ * @return 0, chip busy.
|
|
|
|
-++ */
|
|
|
|
-++static int nfc_device_ready(void)
|
|
|
|
-++{
|
|
|
|
-++ /* Check the ready */
|
|
|
|
-++ return !!(ra_inl(NFC_STATUS) & 0x04);
|
|
|
|
-++}
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * generic function to get data from flash.
|
|
|
|
-++ * @return data length reading from flash.
|
|
|
|
-++ */
|
|
|
|
-++static int _ra_nand_pull_data(char *buf, int len, int use_gdma)
|
|
|
|
-++{
|
|
|
|
-++#ifdef RW_DATA_BY_BYTE
|
|
|
|
-++ char *p = buf;
|
|
|
|
-++#else
|
|
|
|
-++ __u32 *p = (__u32 *)buf;
|
|
|
|
-++#endif
|
|
|
|
-++ int retry, int_st;
|
|
|
|
-++ unsigned int ret_data;
|
|
|
|
-++ int ret_size;
|
|
|
|
-++
|
|
|
|
-++ // receive data by use_gdma
|
|
|
|
-++ if (use_gdma) {
|
|
|
|
-++ //if (_ra_nand_dma_pull((unsigned long)p, len)) {
|
|
|
|
-++ if (1) {
|
|
|
|
-++ printk("%s: fail \n", __func__);
|
|
|
|
-++ len = -1; //return error
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return len;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ //fixme: retry count size?
|
|
|
|
-++ retry = READ_STATUS_RETRY;
|
|
|
|
-++ // no gdma
|
|
|
|
-++ while (len > 0) {
|
|
|
|
-++ int_st = ra_inl(NFC_INT_ST);
|
|
|
|
-++ if (int_st & INT_ST_RX_BUF_RDY) {
|
|
|
|
-++
|
|
|
|
-++ ret_data = ra_inl(NFC_DATA);
|
|
|
|
-++ ra_outl(NFC_INT_ST, INT_ST_RX_BUF_RDY);
|
|
|
|
-++#ifdef RW_DATA_BY_BYTE
|
|
|
|
-++ ret_size = sizeof(unsigned int);
|
|
|
|
-++ ret_size = min(ret_size, len);
|
|
|
|
-++ len -= ret_size;
|
|
|
|
-++ while (ret_size-- > 0) {
|
|
|
|
-++ //nfc is little endian
|
|
|
|
-++ *p++ = ret_data & 0x0ff;
|
|
|
|
-++ ret_data >>= 8;
|
|
|
|
-++ }
|
|
|
|
-++#else
|
|
|
|
-++ ret_size = min(len, 4);
|
|
|
|
-++ len -= ret_size;
|
|
|
|
-++ if (ret_size == 4)
|
|
|
|
-++ *p++ = ret_data;
|
|
|
|
-++ else {
|
|
|
|
-++ __u8 *q = (__u8 *)p;
|
|
|
|
-++ while (ret_size-- > 0) {
|
|
|
|
-++ *q++ = ret_data & 0x0ff;
|
|
|
|
-++ ret_data >>= 8;
|
|
|
|
-++ }
|
|
|
|
-++ p = (__u32 *)q;
|
|
|
|
-++ }
|
|
|
|
-++#endif
|
|
|
|
-++ retry = READ_STATUS_RETRY;
|
|
|
|
-++ }
|
|
|
|
-++ else if (int_st & INT_ST_ND_DONE) {
|
|
|
|
-++ break;
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ udelay(1);
|
|
|
|
-++ if (retry-- < 0)
|
|
|
|
-++ break;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++#ifdef RW_DATA_BY_BYTE
|
|
|
|
-++ return (int)(p - buf);
|
|
|
|
-++#else
|
|
|
|
-++ return ((int)p - (int)buf);
|
|
|
|
-++#endif
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * generic function to put data into flash.
|
|
|
|
-++ * @return data length writing into flash.
|
|
|
|
-++ */
|
|
|
|
-++static int _ra_nand_push_data(char *buf, int len, int use_gdma)
|
|
|
|
-++{
|
|
|
|
-++#ifdef RW_DATA_BY_BYTE
|
|
|
|
-++ char *p = buf;
|
|
|
|
-++#else
|
|
|
|
-++ __u32 *p = (__u32 *)buf;
|
|
|
|
-++#endif
|
|
|
|
-++ int retry, int_st;
|
|
|
|
-++ unsigned int tx_data = 0;
|
|
|
|
-++ int tx_size, iter = 0;
|
|
|
|
-++
|
|
|
|
-++ // receive data by use_gdma
|
|
|
|
-++ if (use_gdma) {
|
|
|
|
-++ //if (_ra_nand_dma_push((unsigned long)p, len))
|
|
|
|
-++ if (1)
|
|
|
|
-++ len = 0;
|
|
|
|
-++ printk("%s: fail \n", __func__);
|
|
|
|
-++ return len;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ // no gdma
|
|
|
|
-++ retry = READ_STATUS_RETRY;
|
|
|
|
-++ while (len > 0) {
|
|
|
|
-++ int_st = ra_inl(NFC_INT_ST);
|
|
|
|
-++ if (int_st & INT_ST_TX_BUF_RDY) {
|
|
|
|
-++#ifdef RW_DATA_BY_BYTE
|
|
|
|
-++ tx_size = min(len, (int)sizeof(unsigned long));
|
|
|
|
-++ for (iter = 0; iter < tx_size; iter++) {
|
|
|
|
-++ tx_data |= (*p++ << (8*iter));
|
|
|
|
-++ }
|
|
|
|
-++#else
|
|
|
|
-++ tx_size = min(len, 4);
|
|
|
|
-++ if (tx_size == 4)
|
|
|
|
-++ tx_data = (*p++);
|
|
|
|
-++ else {
|
|
|
|
-++ __u8 *q = (__u8 *)p;
|
|
|
|
-++ for (iter = 0; iter < tx_size; iter++)
|
|
|
|
-++ tx_data |= (*q++ << (8*iter));
|
|
|
|
-++ p = (__u32 *)q;
|
|
|
|
-++ }
|
|
|
|
-++#endif
|
|
|
|
-++ ra_outl(NFC_INT_ST, INT_ST_TX_BUF_RDY);
|
|
|
|
-++ ra_outl(NFC_DATA, tx_data);
|
|
|
|
-++ len -= tx_size;
|
|
|
|
-++ retry = READ_STATUS_RETRY;
|
|
|
|
-++ }
|
|
|
|
-++ else if (int_st & INT_ST_ND_DONE) {
|
|
|
|
-++ break;
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ udelay(1);
|
|
|
|
-++ if (retry-- < 0) {
|
|
|
|
-++ ra_dbg("%s p:%p buf:%p \n", __func__, p, buf);
|
|
|
|
-++ break;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++#ifdef RW_DATA_BY_BYTE
|
|
|
|
-++ return (int)(p - buf);
|
|
|
|
-++#else
|
|
|
|
-++ return ((int)p - (int)buf);
|
|
|
|
-++#endif
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int nfc_select_chip(struct ra_nand_chip *ra, int chipnr)
|
|
|
|
-++{
|
|
|
|
-++#if (CONFIG_NUMCHIPS == 1)
|
|
|
|
-++ if (!(chipnr < CONFIG_NUMCHIPS))
|
|
|
|
-++ return -1;
|
|
|
|
-++ return 0;
|
|
|
|
-++#else
|
|
|
|
-++ BUG();
|
|
|
|
-++#endif
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/** @return -1: chip_select fail
|
|
|
|
-++ * 0 : both CE and WP==0 are OK
|
|
|
|
-++ * 1 : CE OK and WP==1
|
|
|
|
-++ */
|
|
|
|
-++static int nfc_enable_chip(struct ra_nand_chip *ra, unsigned int offs, int read_only)
|
|
|
|
-++{
|
|
|
|
-++ int chipnr = offs >> ra->chip_shift;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: offs:%x read_only:%x \n", __func__, offs, read_only);
|
|
|
|
-++
|
|
|
|
-++ chipnr = nfc_select_chip(ra, chipnr);
|
|
|
|
-++ if (chipnr < 0) {
|
|
|
|
-++ printk("%s: chip select error, offs(%x)\n", __func__, offs);
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ if (!read_only)
|
|
|
|
-++ return nfc_check_wp();
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/** wait nand chip becomeing ready and return queried status.
|
|
|
|
-++ * @param snooze: sleep time in ms unit before polling device ready.
|
|
|
|
-++ * @return status of nand chip
|
|
|
|
-++ * @return NAN_STATUS_FAIL if something unexpected.
|
|
|
|
-++ */
|
|
|
|
-++static int nfc_wait_ready(int snooze_ms)
|
|
|
|
-++{
|
|
|
|
-++ int retry;
|
|
|
|
-++ char status;
|
|
|
|
-++
|
|
|
|
-++ // wait nfc idle,
|
|
|
|
-++ if (snooze_ms == 0)
|
|
|
|
-++ snooze_ms = 1;
|
|
|
|
-++ else
|
|
|
|
-++ schedule_timeout(snooze_ms * HZ / 1000);
|
|
|
|
-++
|
|
|
|
-++ snooze_ms = retry = snooze_ms *1000000 / 100 ; // ndelay(100)
|
|
|
|
-++
|
|
|
|
-++ while (!NFC_TRANS_DONE() && retry--) {
|
|
|
|
-++ if (!cond_resched())
|
|
|
|
-++ ndelay(100);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ if (!NFC_TRANS_DONE()) {
|
|
|
|
-++ printk("nfc_wait_ready: no transaction done \n");
|
|
|
|
-++ return NAND_STATUS_FAIL;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++#if !defined (CONFIG_NOT_SUPPORT_RB)
|
|
|
|
-++ //fixme
|
|
|
|
-++ while(!(status = nfc_device_ready()) && retry--) {
|
|
|
|
-++ ndelay(100);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ if (status == 0) {
|
|
|
|
-++ printk("nfc_wait_ready: no device ready. \n");
|
|
|
|
-++ return NAND_STATUS_FAIL;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ _nfc_read_status(&status);
|
|
|
|
-++ return status;
|
|
|
|
-++#else
|
|
|
|
-++
|
|
|
|
-++ while(retry--) {
|
|
|
|
-++ _nfc_read_status(&status);
|
|
|
|
-++ if (status & NAND_STATUS_READY)
|
|
|
|
-++ break;
|
|
|
|
-++ ndelay(100);
|
|
|
|
-++ }
|
|
|
|
-++ if (retry<0)
|
|
|
|
-++ printk("nfc_wait_ready 2: no device ready, status(%x). \n", status);
|
|
|
|
-++
|
|
|
|
-++ return status;
|
|
|
|
-++#endif
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * return 0: erase OK
|
|
|
|
-++ * return -EIO: fail
|
|
|
|
-++ */
|
|
|
|
-++int nfc_erase_block(struct ra_nand_chip *ra, int row_addr)
|
|
|
|
-++{
|
|
|
|
-++ unsigned long cmd1, cmd2, bus_addr, conf;
|
|
|
|
-++ char status;
|
|
|
|
-++
|
|
|
|
-++ cmd1 = 0x60;
|
|
|
|
-++ cmd2 = 0xd0;
|
|
|
|
-++ bus_addr = row_addr;
|
|
|
|
-++ conf = 0x00511 | ((CFG_ROW_ADDR_CYCLE)<<16);
|
|
|
|
-++
|
|
|
|
-++ // set NFC
|
|
|
|
-++ ra_dbg("%s: cmd1: %lx, cmd2:%lx bus_addr: %lx, conf: %lx \n",
|
|
|
|
-++ __func__, cmd1, cmd2, bus_addr, conf);
|
|
|
|
-++
|
|
|
|
-++ //fixme, should we check nfc status?
|
|
|
|
-++ CLEAR_INT_STATUS();
|
|
|
|
-++
|
|
|
|
-++ ra_outl(NFC_CMD1, cmd1);
|
|
|
|
-++ ra_outl(NFC_CMD2, cmd2);
|
|
|
|
-++ ra_outl(NFC_ADDR, bus_addr);
|
|
|
|
-++ ra_outl(NFC_CONF, conf);
|
|
|
|
-++
|
|
|
|
-++ status = nfc_wait_ready(3); //erase wait 3ms
|
|
|
|
-++ if (status & NAND_STATUS_FAIL) {
|
|
|
|
-++ printk("%s: fail \n", __func__);
|
|
|
|
-++ return -EIO;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static inline int _nfc_read_raw_data(int cmd1, int cmd2, int bus_addr, int bus_addr2, int conf, char *buf, int len, int flags)
|
|
|
|
-++{
|
|
|
|
-++ int ret;
|
|
|
|
-++
|
|
|
|
-++ CLEAR_INT_STATUS();
|
|
|
|
-++ ra_outl(NFC_CMD1, cmd1);
|
|
|
|
-++ ra_outl(NFC_CMD2, cmd2);
|
|
|
|
-++ ra_outl(NFC_ADDR, bus_addr);
|
|
|
|
-++#if defined (CONFIG_SOC_MT7620)
|
|
|
|
-++ ra_outl(NFC_ADDR2, bus_addr2);
|
|
|
|
-++#endif
|
|
|
|
-++ ra_outl(NFC_CONF, conf);
|
|
|
|
-++
|
|
|
|
-++ ret = _ra_nand_pull_data(buf, len, 0);
|
|
|
|
-++ if (ret != len) {
|
|
|
|
-++ ra_dbg("%s: ret:%x (%x) \n", __func__, ret, len);
|
|
|
|
-++ return NAND_STATUS_FAIL;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ //FIXME, this section is not necessary
|
|
|
|
-++ ret = nfc_wait_ready(0); //wait ready
|
|
|
|
-++ /* to prevent the DATA FIFO 's old data from next operation */
|
|
|
|
-++ ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x02); //clear data buffer
|
|
|
|
-++ ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) & ~0x02); //clear data buffer
|
|
|
|
-++
|
|
|
|
-++ if (ret & NAND_STATUS_FAIL) {
|
|
|
|
-++ printk("%s: fail \n", __func__);
|
|
|
|
-++ return NAND_STATUS_FAIL;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static inline int _nfc_write_raw_data(int cmd1, int cmd3, int bus_addr, int bus_addr2, int conf, char *buf, int len, int flags)
|
|
|
|
-++{
|
|
|
|
-++ int ret;
|
|
|
|
-++
|
|
|
|
-++ CLEAR_INT_STATUS();
|
|
|
|
-++ ra_outl(NFC_CMD1, cmd1);
|
|
|
|
-++ ra_outl(NFC_CMD3, cmd3);
|
|
|
|
-++ ra_outl(NFC_ADDR, bus_addr);
|
|
|
|
-++#if defined (CONFIG_SOC_MT7620)
|
|
|
|
-++ ra_outl(NFC_ADDR2, bus_addr2);
|
|
|
|
-++#endif
|
|
|
|
-++ ra_outl(NFC_CONF, conf);
|
|
|
|
-++
|
|
|
|
-++ ret = _ra_nand_push_data(buf, len, 0);
|
|
|
|
-++ if (ret != len) {
|
|
|
|
-++ ra_dbg("%s: ret:%x (%x) \n", __func__, ret, len);
|
|
|
|
-++ return NAND_STATUS_FAIL;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ ret = nfc_wait_ready(1); //write wait 1ms
|
|
|
|
-++ /* to prevent the DATA FIFO 's old data from next operation */
|
|
|
|
-++ ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x02); //clear data buffer
|
|
|
|
-++ ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) & ~0x02); //clear data buffer
|
|
|
|
-++
|
|
|
|
-++ if (ret & NAND_STATUS_FAIL) {
|
|
|
|
-++ printk("%s: fail \n", __func__);
|
|
|
|
-++ return NAND_STATUS_FAIL;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * @return !0: fail
|
|
|
|
-++ * @return 0: OK
|
|
|
|
-++ */
|
|
|
|
-++int nfc_read_oob(struct ra_nand_chip *ra, int page, unsigned int offs, char *buf, int len, int flags)
|
|
|
|
-++{
|
|
|
|
-++ unsigned int cmd1 = 0, cmd2 = 0, conf = 0;
|
|
|
|
-++ unsigned int bus_addr = 0, bus_addr2 = 0;
|
|
|
|
-++ unsigned int ecc_en;
|
|
|
|
-++ int use_gdma;
|
|
|
|
-++ int status;
|
|
|
|
-++
|
|
|
|
-++ int pages_perblock = 1<<(ra->erase_shift - ra->page_shift);
|
|
|
|
-++ // constrain of nfc read function
|
|
|
|
-++
|
|
|
|
-++#if defined (WORKAROUND_RX_BUF_OV)
|
|
|
|
-++ BUG_ON (len > 60); //problem of rx-buffer overrun
|
|
|
|
-++#endif
|
|
|
|
-++ BUG_ON (offs >> ra->oob_shift); //page boundry
|
|
|
|
-++ BUG_ON ((unsigned int)(((offs + len) >> ra->oob_shift) + page) >
|
|
|
|
-++ ((page + pages_perblock) & ~(pages_perblock-1))); //block boundry
|
|
|
|
-++
|
|
|
|
-++ use_gdma = flags & FLAG_USE_GDMA;
|
|
|
|
-++ ecc_en = flags & FLAG_ECC_EN;
|
|
|
|
-++ bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)) | (offs & ((1<<CFG_COLUMN_ADDR_CYCLE*8) - 1));
|
|
|
|
-++
|
|
|
|
-++ if (is_nand_page_2048) {
|
|
|
|
-++ bus_addr += CFG_PAGESIZE;
|
|
|
|
-++ bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
|
|
|
|
-++ cmd1 = 0x0;
|
|
|
|
-++ cmd2 = 0x30;
|
|
|
|
-++ conf = 0x000511| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ cmd1 = 0x50;
|
|
|
|
-++ conf = 0x000141| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
|
|
|
|
-++ }
|
|
|
|
-++ if (ecc_en)
|
|
|
|
-++ conf |= (1<<3);
|
|
|
|
-++ if (use_gdma)
|
|
|
|
-++ conf |= (1<<2);
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: cmd1:%x, bus_addr:%x, conf:%x, len:%x, flag:%x\n",
|
|
|
|
-++ __func__, cmd1, bus_addr, conf, len, flags);
|
|
|
|
-++
|
|
|
|
-++ status = _nfc_read_raw_data(cmd1, cmd2, bus_addr, bus_addr2, conf, buf, len, flags);
|
|
|
|
-++ if (status & NAND_STATUS_FAIL) {
|
|
|
|
-++ printk("%s: fail\n", __func__);
|
|
|
|
-++ return -EIO;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * @return !0: fail
|
|
|
|
-++ * @return 0: OK
|
|
|
|
-++ */
|
|
|
|
-++int nfc_write_oob(struct ra_nand_chip *ra, int page, unsigned int offs, char *buf, int len, int flags)
|
|
|
|
-++{
|
|
|
|
-++ unsigned int cmd1 = 0, cmd3=0, conf = 0;
|
|
|
|
-++ unsigned int bus_addr = 0, bus_addr2 = 0;
|
|
|
|
-++ int use_gdma;
|
|
|
|
-++ int status;
|
|
|
|
-++
|
|
|
|
-++ int pages_perblock = 1<<(ra->erase_shift - ra->page_shift);
|
|
|
|
-++ // constrain of nfc read function
|
|
|
|
-++
|
|
|
|
-++ BUG_ON (offs >> ra->oob_shift); //page boundry
|
|
|
|
-++ BUG_ON ((unsigned int)(((offs + len) >> ra->oob_shift) + page) >
|
|
|
|
-++ ((page + pages_perblock) & ~(pages_perblock-1))); //block boundry
|
|
|
|
-++
|
|
|
|
-++ use_gdma = flags & FLAG_USE_GDMA;
|
|
|
|
-++ bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)) | (offs & ((1<<CFG_COLUMN_ADDR_CYCLE*8) - 1));
|
|
|
|
-++
|
|
|
|
-++ if (is_nand_page_2048) {
|
|
|
|
-++ cmd1 = 0x80;
|
|
|
|
-++ cmd3 = 0x10;
|
|
|
|
-++ bus_addr += CFG_PAGESIZE;
|
|
|
|
-++ bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
|
|
|
|
-++ conf = 0x001123 | ((CFG_ADDR_CYCLE)<<16) | ((len) << 20);
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ cmd1 = 0x08050;
|
|
|
|
-++ cmd3 = 0x10;
|
|
|
|
-++ conf = 0x001223 | ((CFG_ADDR_CYCLE)<<16) | ((len) << 20);
|
|
|
|
-++ }
|
|
|
|
-++ if (use_gdma)
|
|
|
|
-++ conf |= (1<<2);
|
|
|
|
-++
|
|
|
|
-++ // set NFC
|
|
|
|
-++ ra_dbg("%s: cmd1: %x, cmd3: %x bus_addr: %x, conf: %x, len:%x\n",
|
|
|
|
-++ __func__, cmd1, cmd3, bus_addr, conf, len);
|
|
|
|
-++
|
|
|
|
-++ status = _nfc_write_raw_data(cmd1, cmd3, bus_addr, bus_addr2, conf, buf, len, flags);
|
|
|
|
-++ if (status & NAND_STATUS_FAIL) {
|
|
|
|
-++ printk("%s: fail \n", __func__);
|
|
|
|
-++ return -EIO;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++int nfc_read_page(struct ra_nand_chip *ra, char *buf, int page, int flags);
|
|
|
|
-++int nfc_write_page(struct ra_nand_chip *ra, char *buf, int page, int flags);
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++#if !defined (WORKAROUND_RX_BUF_OV)
|
|
|
|
-++static int one_bit_correction(char *ecc, char *expected, int *bytes, int *bits);
|
|
|
|
-++int nfc_ecc_verify(struct ra_nand_chip *ra, char *buf, int page, int mode)
|
|
|
|
-++{
|
|
|
|
-++ int ret, i;
|
|
|
|
-++ char *p, *e;
|
|
|
|
-++ int ecc;
|
|
|
|
-++
|
|
|
|
-++ //ra_dbg("%s, page:%x mode:%d\n", __func__, page, mode);
|
|
|
|
-++
|
|
|
|
-++ if (mode == FL_WRITING) {
|
|
|
|
-++ int len = CFG_PAGESIZE + CFG_PAGE_OOBSIZE;
|
|
|
|
-++ int conf = 0x000141| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
|
|
|
|
-++ conf |= (1<<3); //(ecc_en)
|
|
|
|
-++ //conf |= (1<<2); // (use_gdma)
|
|
|
|
-++
|
|
|
|
-++ p = ra->readback_buffers;
|
|
|
|
-++ ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_ECC_EN);
|
|
|
|
-++ if (ret == 0)
|
|
|
|
-++ goto ecc_check;
|
|
|
|
-++
|
|
|
|
-++ //FIXME, double comfirm
|
|
|
|
-++ printk("%s: read back fail, try again \n",__func__);
|
|
|
|
-++ ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_ECC_EN);
|
|
|
|
-++ if (ret != 0) {
|
|
|
|
-++ printk("\t%s: read back fail agian \n",__func__);
|
|
|
|
-++ goto bad_block;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ else if (mode == FL_READING) {
|
|
|
|
-++ p = buf;
|
|
|
|
-++ }
|
|
|
|
-++ else
|
|
|
|
-++ return -2;
|
|
|
|
-++
|
|
|
|
-++ecc_check:
|
|
|
|
-++ p += CFG_PAGESIZE;
|
|
|
|
-++ if (!is_nand_page_2048) {
|
|
|
|
-++ ecc = ra_inl(NFC_ECC);
|
|
|
|
-++ if (ecc == 0) //clean page.
|
|
|
|
-++ return 0;
|
|
|
|
-++ e = (char*)&ecc;
|
|
|
|
-++ for (i=0; i<CONFIG_ECC_BYTES; i++) {
|
|
|
|
-++ int eccpos = CONFIG_ECC_OFFSET + i;
|
|
|
|
-++ if (*(p + eccpos) != (char)0xff)
|
|
|
|
-++ break;
|
|
|
|
-++ if (i == CONFIG_ECC_BYTES - 1) {
|
|
|
|
-++ printk("skip ecc 0xff at page %x\n", page);
|
|
|
|
-++ return 0;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ for (i=0; i<CONFIG_ECC_BYTES; i++) {
|
|
|
|
-++ int eccpos = CONFIG_ECC_OFFSET + i;
|
|
|
|
-++ if (*(p + eccpos) != *(e + i)) {
|
|
|
|
-++ printk("%s mode:%s, invalid ecc, page: %x read:%x %x %x, ecc:%x \n",
|
|
|
|
-++ __func__, (mode == FL_READING)?"read":"write", page,
|
|
|
|
-++ *(p+ CONFIG_ECC_OFFSET), *(p+ CONFIG_ECC_OFFSET+1), *(p+ CONFIG_ECC_OFFSET +2), ecc);
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++#if defined (CONFIG_SOC_MT7620)
|
|
|
|
-++ else {
|
|
|
|
-++ int ecc2, ecc3, ecc4, qsz;
|
|
|
|
-++ char *e2, *e3, *e4;
|
|
|
|
-++ int correction_flag = 0;
|
|
|
|
-++ ecc = ra_inl(NFC_ECC_P1);
|
|
|
|
-++ ecc2 = ra_inl(NFC_ECC_P2);
|
|
|
|
-++ ecc3 = ra_inl(NFC_ECC_P3);
|
|
|
|
-++ ecc4 = ra_inl(NFC_ECC_P4);
|
|
|
|
-++ e = (char*)&ecc;
|
|
|
|
-++ e2 = (char*)&ecc2;
|
|
|
|
-++ e3 = (char*)&ecc3;
|
|
|
|
-++ e4 = (char*)&ecc4;
|
|
|
|
-++ qsz = CFG_PAGE_OOBSIZE / 4;
|
|
|
|
-++ if (ecc == 0 && ecc2 == 0 && ecc3 == 0 && ecc4 == 0)
|
|
|
|
-++ return 0;
|
|
|
|
-++ for (i=0; i<CONFIG_ECC_BYTES; i++) {
|
|
|
|
-++ int eccpos = CONFIG_ECC_OFFSET + i;
|
|
|
|
-++ if (*(p + eccpos) != (char)0xff)
|
|
|
|
-++ break;
|
|
|
|
-++ else if (*(p + eccpos + qsz) != (char)0xff)
|
|
|
|
-++ break;
|
|
|
|
-++ else if (*(p + eccpos + qsz*2) != (char)0xff)
|
|
|
|
-++ break;
|
|
|
|
-++ else if (*(p + eccpos + qsz*3) != (char)0xff)
|
|
|
|
-++ break;
|
|
|
|
-++ if (i == CONFIG_ECC_BYTES - 1) {
|
|
|
|
-++ printk("skip ecc 0xff at page %x\n", page);
|
|
|
|
-++ return 0;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ for (i=0; i<CONFIG_ECC_BYTES; i++) {
|
|
|
|
-++ int eccpos = CONFIG_ECC_OFFSET + i;
|
|
|
|
-++ if (*(p + eccpos) != *(e + i)) {
|
|
|
|
-++ printk("%s mode:%s, invalid ecc, page: %x read:%x %x %x, ecc:%x \n",
|
|
|
|
-++ __func__, (mode == FL_READING)?"read":"write", page,
|
|
|
|
-++ *(p+ CONFIG_ECC_OFFSET), *(p+ CONFIG_ECC_OFFSET+1), *(p+ CONFIG_ECC_OFFSET +2), ecc);
|
|
|
|
-++ correction_flag |= 0x1;
|
|
|
|
-++ }
|
|
|
|
-++ if (*(p + eccpos + qsz) != *(e2 + i)) {
|
|
|
|
-++ printk("%s mode:%s, invalid ecc2, page: %x read:%x %x %x, ecc2:%x \n",
|
|
|
|
-++ __func__, (mode == FL_READING)?"read":"write", page,
|
|
|
|
-++ *(p+CONFIG_ECC_OFFSET+qsz), *(p+ CONFIG_ECC_OFFSET+1+qsz), *(p+ CONFIG_ECC_OFFSET+2+qsz), ecc2);
|
|
|
|
-++ correction_flag |= 0x2;
|
|
|
|
-++ }
|
|
|
|
-++ if (*(p + eccpos + qsz*2) != *(e3 + i)) {
|
|
|
|
-++ printk("%s mode:%s, invalid ecc3, page: %x read:%x %x %x, ecc3:%x \n",
|
|
|
|
-++ __func__, (mode == FL_READING)?"read":"write", page,
|
|
|
|
-++ *(p+CONFIG_ECC_OFFSET+qsz*2), *(p+ CONFIG_ECC_OFFSET+1+qsz*2), *(p+ CONFIG_ECC_OFFSET+2+qsz*2), ecc3);
|
|
|
|
-++ correction_flag |= 0x4;
|
|
|
|
-++ }
|
|
|
|
-++ if (*(p + eccpos + qsz*3) != *(e4 + i)) {
|
|
|
|
-++ printk("%s mode:%s, invalid ecc4, page: %x read:%x %x %x, ecc4:%x \n",
|
|
|
|
-++ __func__, (mode == FL_READING)?"read":"write", page,
|
|
|
|
-++ *(p+CONFIG_ECC_OFFSET+qsz*3), *(p+ CONFIG_ECC_OFFSET+1+qsz*3), *(p+ CONFIG_ECC_OFFSET+2+qsz*3), ecc4);
|
|
|
|
-++ correction_flag |= 0x8;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ if (correction_flag)
|
|
|
|
-++ {
|
|
|
|
-++ printk("trying to do correction!\n");
|
|
|
|
-++ if (correction_flag & 0x1)
|
|
|
|
-++ {
|
|
|
|
-++ int bytes, bits;
|
|
|
|
-++ char *pBuf = p - CFG_PAGESIZE;
|
|
|
|
-++
|
|
|
|
-++ if (one_bit_correction(p + CONFIG_ECC_OFFSET, e, &bytes, &bits) == 0)
|
|
|
|
-++ {
|
|
|
|
-++ pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
|
|
|
|
-++ printk("1. correct byte %d, bit %d!\n", bytes, bits);
|
|
|
|
-++ }
|
|
|
|
-++ else
|
|
|
|
-++ {
|
|
|
|
-++ printk("failed to correct!\n");
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ if (correction_flag & 0x2)
|
|
|
|
-++ {
|
|
|
|
-++ int bytes, bits;
|
|
|
|
-++ char *pBuf = (p - CFG_PAGESIZE) + CFG_PAGESIZE/4;
|
|
|
|
-++
|
|
|
|
-++ if (one_bit_correction((p + CONFIG_ECC_OFFSET + qsz), e2, &bytes, &bits) == 0)
|
|
|
|
-++ {
|
|
|
|
-++ pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
|
|
|
|
-++ printk("2. correct byte %d, bit %d!\n", bytes, bits);
|
|
|
|
-++ }
|
|
|
|
-++ else
|
|
|
|
-++ {
|
|
|
|
-++ printk("failed to correct!\n");
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ if (correction_flag & 0x4)
|
|
|
|
-++ {
|
|
|
|
-++ int bytes, bits;
|
|
|
|
-++ char *pBuf = (p - CFG_PAGESIZE) + CFG_PAGESIZE/2;
|
|
|
|
-++
|
|
|
|
-++ if (one_bit_correction((p + CONFIG_ECC_OFFSET + qsz * 2), e3, &bytes, &bits) == 0)
|
|
|
|
-++ {
|
|
|
|
-++ pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
|
|
|
|
-++ printk("3. correct byte %d, bit %d!\n", bytes, bits);
|
|
|
|
-++ }
|
|
|
|
-++ else
|
|
|
|
-++ {
|
|
|
|
-++ printk("failed to correct!\n");
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ if (correction_flag & 0x8)
|
|
|
|
-++ {
|
|
|
|
-++ int bytes, bits;
|
|
|
|
-++ char *pBuf = (p - CFG_PAGESIZE) + CFG_PAGESIZE*3/4;
|
|
|
|
-++
|
|
|
|
-++ if (one_bit_correction((p + CONFIG_ECC_OFFSET + qsz * 3), e4, &bytes, &bits) == 0)
|
|
|
|
-++ {
|
|
|
|
-++ pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
|
|
|
|
-++ printk("4. correct byte %d, bit %d!\n", bytes, bits);
|
|
|
|
-++ }
|
|
|
|
-++ else
|
|
|
|
-++ {
|
|
|
|
-++ printk("failed to correct!\n");
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ }
|
|
|
|
-++#endif
|
|
|
|
-++ return 0;
|
|
|
|
-++
|
|
|
|
-++bad_block:
|
|
|
|
-++ return -1;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++#else
|
|
|
|
-++
|
|
|
|
-++void ranfc_dump(void)
|
|
|
|
-++{
|
|
|
|
-++ int i;
|
|
|
|
-++ for (i=0; i<11; i++) {
|
|
|
|
-++ if (i==6)
|
|
|
|
-++ continue;
|
|
|
|
-++ printk("%x: %x \n", NFC_BASE + i*4, ra_inl(NFC_BASE + i*4));
|
|
|
|
-++ }
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * @return 0, ecc OK or corrected.
|
|
|
|
-++ * @return NAND_STATUS_FAIL, ecc fail.
|
|
|
|
-++ */
|
|
|
|
-++
|
|
|
|
-++int nfc_ecc_verify(struct ra_nand_chip *ra, char *buf, int page, int mode)
|
|
|
|
-++{
|
|
|
|
-++ int ret, i;
|
|
|
|
-++ char *p, *e;
|
|
|
|
-++ int ecc;
|
|
|
|
-++
|
|
|
|
-++ if (ranfc_verify == 0)
|
|
|
|
-++ return 0;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s, page:%x mode:%d\n", __func__, page, mode);
|
|
|
|
-++
|
|
|
|
-++ if (mode == FL_WRITING) { // read back and memcmp
|
|
|
|
-++ ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_NONE);
|
|
|
|
-++ if (ret != 0) //double comfirm
|
|
|
|
-++ ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_NONE);
|
|
|
|
-++
|
|
|
|
-++ if (ret != 0) {
|
|
|
|
-++ printk("%s: mode:%x read back fail \n", __func__, mode);
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++ return memcmp(buf, ra->readback_buffers, 1<<ra->page_shift);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ if (mode == FL_READING) {
|
|
|
|
-++#if 0
|
|
|
|
-++ if (ra->sandbox_page == 0)
|
|
|
|
-++ return 0;
|
|
|
|
-++
|
|
|
|
-++ ret = nfc_write_page(ra, buf, ra->sandbox_page, FLAG_USE_GDMA | FLAG_ECC_EN);
|
|
|
|
-++ if (ret != 0) {
|
|
|
|
-++ printk("%s, fail write sandbox_page \n", __func__);
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++#else
|
|
|
|
-++ /** @note:
|
|
|
|
-++ * The following command is actually not 'write' command to drive NFC to write flash.
|
|
|
|
-++ * However, it can make NFC to calculate ECC, that will be used to compare with original ones.
|
|
|
|
-++ * --YT
|
|
|
|
-++ */
|
|
|
|
-++ unsigned int conf = 0x001223| (CFG_ADDR_CYCLE<<16) | (0x200 << 20) | (1<<3) | (1<<2);
|
|
|
|
-++ _nfc_write_raw_data(0xff, 0xff, ra->sandbox_page<<ra->page_shift, conf, buf, 0x200, FLAG_USE_GDMA);
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++ ecc = ra_inl(NFC_ECC);
|
|
|
|
-++ if (ecc == 0) //clean page.
|
|
|
|
-++ return 0;
|
|
|
|
-++ e = (char*)&ecc;
|
|
|
|
-++ p = buf + (1<<ra->page_shift);
|
|
|
|
-++ for (i=0; i<CONFIG_ECC_BYTES; i++) {
|
|
|
|
-++ int eccpos = CONFIG_ECC_OFFSET + i;
|
|
|
|
-++ if (*(p + eccpos) != *(e + i)) {
|
|
|
|
-++ printk("%s mode:%s, invalid ecc, page: %x read:%x %x %x, write:%x \n",
|
|
|
|
-++ __func__, (mode == FL_READING)?"read":"write", page,
|
|
|
|
-++ *(p+ CONFIG_ECC_OFFSET), *(p+ CONFIG_ECC_OFFSET+1), *(p+ CONFIG_ECC_OFFSET +2), ecc);
|
|
|
|
-++
|
|
|
|
-++ for (i=0; i<528; i++)
|
|
|
|
-++ printk("%-2x \n", *(buf + i));
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ return 0;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return -1;
|
|
|
|
-++}
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * @return -EIO, writing size is less than a page
|
|
|
|
-++ * @return 0, OK
|
|
|
|
-++ */
|
|
|
|
-++int nfc_read_page(struct ra_nand_chip *ra, char *buf, int page, int flags)
|
|
|
|
-++{
|
|
|
|
-++ unsigned int cmd1 = 0, cmd2 = 0, conf = 0;
|
|
|
|
-++ unsigned int bus_addr = 0, bus_addr2 = 0;
|
|
|
|
-++ unsigned int ecc_en;
|
|
|
|
-++ int use_gdma;
|
|
|
|
-++ int size, offs;
|
|
|
|
-++ int status = 0;
|
|
|
|
-++
|
|
|
|
-++ use_gdma = flags & FLAG_USE_GDMA;
|
|
|
|
-++ ecc_en = flags & FLAG_ECC_EN;
|
|
|
|
-++
|
|
|
|
-++ page = page & (CFG_CHIPSIZE - 1); // chip boundary
|
|
|
|
-++ size = CFG_PAGESIZE + CFG_PAGE_OOBSIZE; //add oobsize
|
|
|
|
-++ offs = 0;
|
|
|
|
-++
|
|
|
|
-++ while (size > 0) {
|
|
|
|
-++ int len;
|
|
|
|
-++#if defined (WORKAROUND_RX_BUF_OV)
|
|
|
|
-++ len = min(60, size);
|
|
|
|
-++#else
|
|
|
|
-++ len = size;
|
|
|
|
-++#endif
|
|
|
|
-++ bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)) | (offs & ((1<<CFG_COLUMN_ADDR_CYCLE*8)-1));
|
|
|
|
-++ if (is_nand_page_2048) {
|
|
|
|
-++ bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
|
|
|
|
-++ cmd1 = 0x0;
|
|
|
|
-++ cmd2 = 0x30;
|
|
|
|
-++ conf = 0x000511| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ if (offs & ~(CFG_PAGESIZE-1))
|
|
|
|
-++ cmd1 = 0x50;
|
|
|
|
-++ else if (offs & ~((1<<CFG_COLUMN_ADDR_CYCLE*8)-1))
|
|
|
|
-++ cmd1 = 0x01;
|
|
|
|
-++ else
|
|
|
|
-++ cmd1 = 0;
|
|
|
|
-++
|
|
|
|
-++ conf = 0x000141| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
|
|
|
|
-++ }
|
|
|
|
-++#if !defined (WORKAROUND_RX_BUF_OV)
|
|
|
|
-++ if (ecc_en)
|
|
|
|
-++ conf |= (1<<3);
|
|
|
|
-++#endif
|
|
|
|
-++ if (use_gdma)
|
|
|
|
-++ conf |= (1<<2);
|
|
|
|
-++
|
|
|
|
-++ status = _nfc_read_raw_data(cmd1, cmd2, bus_addr, bus_addr2, conf, buf+offs, len, flags);
|
|
|
|
-++ if (status & NAND_STATUS_FAIL) {
|
|
|
|
-++ printk("%s: fail \n", __func__);
|
|
|
|
-++ return -EIO;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ offs += len;
|
|
|
|
-++ size -= len;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ // verify and correct ecc
|
|
|
|
-++ if ((flags & (FLAG_VERIFY | FLAG_ECC_EN)) == (FLAG_VERIFY | FLAG_ECC_EN)) {
|
|
|
|
-++ status = nfc_ecc_verify(ra, buf, page, FL_READING);
|
|
|
|
-++ if (status != 0) {
|
|
|
|
-++ printk("%s: fail, buf:%x, page:%x, flag:%x\n",
|
|
|
|
-++ __func__, (unsigned int)buf, page, flags);
|
|
|
|
-++ return -EBADMSG;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ // fix,e not yet support
|
|
|
|
-++ ra->buffers_page = -1; //cached
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * @return -EIO, fail to write
|
|
|
|
-++ * @return 0, OK
|
|
|
|
-++ */
|
|
|
|
-++int nfc_write_page(struct ra_nand_chip *ra, char *buf, int page, int flags)
|
|
|
|
-++{
|
|
|
|
-++ unsigned int cmd1 = 0, cmd3, conf = 0;
|
|
|
|
-++ unsigned int bus_addr = 0, bus_addr2 = 0;
|
|
|
|
-++ unsigned int ecc_en;
|
|
|
|
-++ int use_gdma;
|
|
|
|
-++ int size;
|
|
|
|
-++ char status;
|
|
|
|
-++ uint8_t *oob = buf + (1<<ra->page_shift);
|
|
|
|
-++
|
|
|
|
-++ use_gdma = flags & FLAG_USE_GDMA;
|
|
|
|
-++ ecc_en = flags & FLAG_ECC_EN;
|
|
|
|
-++
|
|
|
|
-++ oob[ra->badblockpos] = 0xff; //tag as good block.
|
|
|
|
-++ ra->buffers_page = -1; //cached
|
|
|
|
-++
|
|
|
|
-++ page = page & (CFG_CHIPSIZE-1); //chip boundary
|
|
|
|
-++ size = CFG_PAGESIZE + CFG_PAGE_OOBSIZE; //add oobsize
|
|
|
|
-++ bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)); //write_page always write from offset 0.
|
|
|
|
-++
|
|
|
|
-++ if (is_nand_page_2048) {
|
|
|
|
-++ bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
|
|
|
|
-++ cmd1 = 0x80;
|
|
|
|
-++ cmd3 = 0x10;
|
|
|
|
-++ conf = 0x001123| ((CFG_ADDR_CYCLE)<<16) | (size << 20);
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ cmd1 = 0x8000;
|
|
|
|
-++ cmd3 = 0x10;
|
|
|
|
-++ conf = 0x001223| ((CFG_ADDR_CYCLE)<<16) | (size << 20);
|
|
|
|
-++ }
|
|
|
|
-++ if (ecc_en)
|
|
|
|
-++ conf |= (1<<3); //enable ecc
|
|
|
|
-++ if (use_gdma)
|
|
|
|
-++ conf |= (1<<2);
|
|
|
|
-++
|
|
|
|
-++ // set NFC
|
|
|
|
-++ ra_dbg("nfc_write_page: cmd1: %x, cmd3: %x bus_addr: %x, conf: %x, len:%x\n",
|
|
|
|
-++ cmd1, cmd3, bus_addr, conf, size);
|
|
|
|
-++
|
|
|
|
-++ status = _nfc_write_raw_data(cmd1, cmd3, bus_addr, bus_addr2, conf, buf, size, flags);
|
|
|
|
-++ if (status & NAND_STATUS_FAIL) {
|
|
|
|
-++ printk("%s: fail \n", __func__);
|
|
|
|
-++ return -EIO;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++ if (flags & FLAG_VERIFY) { // verify and correct ecc
|
|
|
|
-++ status = nfc_ecc_verify(ra, buf, page, FL_WRITING);
|
|
|
|
-++
|
|
|
|
-++#ifdef RANDOM_GEN_BAD_BLOCK
|
|
|
|
-++ if (((random32() & 0x1ff) == 0x0) && (page >= 0x100)) // randomly create bad block
|
|
|
|
-++ {
|
|
|
|
-++ printk("hmm... create a bad block at page %x\n", (bus_addr >> 16));
|
|
|
|
-++ status = -1;
|
|
|
|
-++ }
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++ if (status != 0) {
|
|
|
|
-++ printk("%s: ecc_verify fail: ret:%x \n", __func__, status);
|
|
|
|
-++ oob[ra->badblockpos] = 0x33;
|
|
|
|
-++ page -= page % (CFG_BLOCKSIZE/CFG_PAGESIZE);
|
|
|
|
-++ printk("create a bad block at page %x\n", page);
|
|
|
|
-++ if (!is_nand_page_2048)
|
|
|
|
-++ status = nfc_write_oob(ra, page, ra->badblockpos, oob+ra->badblockpos, 1, flags);
|
|
|
|
-++ else
|
|
|
|
-++ {
|
|
|
|
-++ status = _nfc_write_raw_data(cmd1, cmd3, bus_addr, bus_addr2, conf, buf, size, flags);
|
|
|
|
-++ nfc_write_oob(ra, page, 0, oob, 16, FLAG_NONE);
|
|
|
|
-++ }
|
|
|
|
-++ return -EBADMSG;
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ ra->buffers_page = page; //cached
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++/*************************************************************
|
|
|
|
-++ * nand internal process
|
|
|
|
-++ *************************************************************/
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * nand_release_device - [GENERIC] release chip
|
|
|
|
-++ * @mtd: MTD device structure
|
|
|
|
-++ *
|
|
|
|
-++ * Deselect, release chip lock and wake up anyone waiting on the device
|
|
|
|
-++ */
|
|
|
|
-++static void nand_release_device(struct ra_nand_chip *ra)
|
|
|
|
-++{
|
|
|
|
-++ /* De-select the NAND device */
|
|
|
|
-++ nfc_select_chip(ra, -1);
|
|
|
|
-++
|
|
|
|
-++ /* Release the controller and the chip */
|
|
|
|
-++ ra->state = FL_READY;
|
|
|
|
-++
|
|
|
|
-++ mutex_unlock(ra->controller);
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * nand_get_device - [GENERIC] Get chip for selected access
|
|
|
|
-++ * @chip: the nand chip descriptor
|
|
|
|
-++ * @mtd: MTD device structure
|
|
|
|
-++ * @new_state: the state which is requested
|
|
|
|
-++ *
|
|
|
|
-++ * Get the device and lock it for exclusive access
|
|
|
|
-++ */
|
|
|
|
-++static int
|
|
|
|
-++nand_get_device(struct ra_nand_chip *ra, int new_state)
|
|
|
|
-++{
|
|
|
|
-++ int ret = 0;
|
|
|
|
-++
|
|
|
|
-++ ret = mutex_lock_interruptible(ra->controller);
|
|
|
|
-++ if (!ret)
|
|
|
|
-++ ra->state = new_state;
|
|
|
|
-++
|
|
|
|
-++ return ret;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/*************************************************************
|
|
|
|
-++ * nand internal process
|
|
|
|
-++ *************************************************************/
|
|
|
|
-++
|
|
|
|
-++int ra_nand_bbt_get(struct ra_nand_chip *ra, int block)
|
|
|
|
-++{
|
|
|
|
-++ int byte, bits;
|
|
|
|
-++ bits = block * BBTTAG_BITS;
|
|
|
|
-++
|
|
|
|
-++ byte = bits / 8;
|
|
|
|
-++ bits = bits % 8;
|
|
|
|
-++
|
|
|
|
-++ return (ra->bbt[byte] >> bits) & BBTTAG_BITS_MASK;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++int ra_nand_bbt_set(struct ra_nand_chip *ra, int block, int tag)
|
|
|
|
-++{
|
|
|
|
-++ int byte, bits;
|
|
|
|
-++ bits = block * BBTTAG_BITS;
|
|
|
|
-++
|
|
|
|
-++ byte = bits / 8;
|
|
|
|
-++ bits = bits % 8;
|
|
|
|
-++
|
|
|
|
-++ // If previous tag is bad, dont overwrite it
|
|
|
|
-++ if (((ra->bbt[byte] >> bits) & BBTTAG_BITS_MASK) == BBT_TAG_BAD)
|
|
|
|
-++ {
|
|
|
|
-++ return BBT_TAG_BAD;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ ra->bbt[byte] = (ra->bbt[byte] & ~(BBTTAG_BITS_MASK << bits)) | ((tag & BBTTAG_BITS_MASK) << bits);
|
|
|
|
-++
|
|
|
|
-++ return tag;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * nand_block_checkbad - [GENERIC] Check if a block is marked bad
|
|
|
|
-++ * @mtd: MTD device structure
|
|
|
|
-++ * @ofs: offset from device start
|
|
|
|
-++ *
|
|
|
|
-++ * Check, if the block is bad. Either by reading the bad block table or
|
|
|
|
-++ * calling of the scan function.
|
|
|
|
-++ */
|
|
|
|
-++int nand_block_checkbad(struct ra_nand_chip *ra, loff_t offs)
|
|
|
|
-++{
|
|
|
|
-++ int page, block;
|
|
|
|
-++ int ret = 4;
|
|
|
|
-++ unsigned int tag;
|
|
|
|
-++ char *str[]= {"UNK", "RES", "BAD", "GOOD"};
|
|
|
|
-++
|
|
|
|
-++ if (ranfc_bbt == 0)
|
|
|
|
-++ return 0;
|
|
|
|
-++
|
|
|
|
-++ {
|
|
|
|
-++ // align with chip
|
|
|
|
-++
|
|
|
|
-++ offs = offs & ((1<<ra->chip_shift) -1);
|
|
|
|
-++
|
|
|
|
-++ page = offs >> ra->page_shift;
|
|
|
|
-++ block = offs >> ra->erase_shift;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ tag = ra_nand_bbt_get(ra, block);
|
|
|
|
-++
|
|
|
|
-++ if (tag == BBT_TAG_UNKNOWN) {
|
|
|
|
-++ ret = nfc_read_oob(ra, page, ra->badblockpos, (char*)&tag, 1, FLAG_NONE);
|
|
|
|
-++ if (ret == 0)
|
|
|
|
-++ tag = ((le32_to_cpu(tag) & 0x0ff) == 0x0ff) ? BBT_TAG_GOOD : BBT_TAG_BAD;
|
|
|
|
-++ else
|
|
|
|
-++ tag = BBT_TAG_BAD;
|
|
|
|
-++
|
|
|
|
-++ ra_nand_bbt_set(ra, block, tag);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ if (tag != BBT_TAG_GOOD) {
|
|
|
|
-++ printk("%s: offs:%x tag: %s \n", __func__, (unsigned int)offs, str[tag]);
|
|
|
|
-++ return 1;
|
|
|
|
-++ }
|
|
|
|
-++ else
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * nand_block_markbad -
|
|
|
|
-++ */
|
|
|
|
-++int nand_block_markbad(struct ra_nand_chip *ra, loff_t offs)
|
|
|
|
-++{
|
|
|
|
-++ int page, block;
|
|
|
|
-++ int ret = 4;
|
|
|
|
-++ unsigned int tag;
|
|
|
|
-++ char *ecc;
|
|
|
|
-++
|
|
|
|
-++ // align with chip
|
|
|
|
-++ ra_dbg("%s offs: %x \n", __func__, (int)offs);
|
|
|
|
-++
|
|
|
|
-++ offs = offs & ((1<<ra->chip_shift) -1);
|
|
|
|
-++
|
|
|
|
-++ page = offs >> ra->page_shift;
|
|
|
|
-++ block = offs >> ra->erase_shift;
|
|
|
|
-++
|
|
|
|
-++ tag = ra_nand_bbt_get(ra, block);
|
|
|
|
-++
|
|
|
|
-++ if (tag == BBT_TAG_BAD) {
|
|
|
|
-++ printk("%s: mark repeatedly \n", __func__);
|
|
|
|
-++ return 0;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ // new tag as bad
|
|
|
|
-++ tag =BBT_TAG_BAD;
|
|
|
|
-++ ret = nfc_read_page(ra, ra->buffers, page, FLAG_NONE);
|
|
|
|
-++ if (ret != 0) {
|
|
|
|
-++ printk("%s: fail to read bad block tag \n", __func__);
|
|
|
|
-++ goto tag_bbt;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ ecc = &ra->buffers[(1<<ra->page_shift)+ra->badblockpos];
|
|
|
|
-++ if (*ecc == (char)0x0ff) {
|
|
|
|
-++ //tag into flash
|
|
|
|
-++ *ecc = (char)tag;
|
|
|
|
-++ ret = nfc_write_page(ra, ra->buffers, page, FLAG_USE_GDMA);
|
|
|
|
-++ if (ret)
|
|
|
|
-++ printk("%s: fail to write bad block tag \n", __func__);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++tag_bbt:
|
|
|
|
-++ //update bbt
|
|
|
|
-++ ra_nand_bbt_set(ra, block, tag);
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++#if defined (WORKAROUND_RX_BUF_OV)
|
|
|
|
-++/**
|
|
|
|
-++ * to find a bad block for ecc verify of read_page
|
|
|
|
-++ */
|
|
|
|
-++unsigned int nand_bbt_find_sandbox(struct ra_nand_chip *ra)
|
|
|
|
-++{
|
|
|
|
-++ loff_t offs = 0;
|
|
|
|
-++ int chipsize = 1 << ra->chip_shift;
|
|
|
|
-++ int blocksize = 1 << ra->erase_shift;
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++ while (offs < chipsize) {
|
|
|
|
-++ if (nand_block_checkbad(ra, offs)) //scan and verify the unknown tag
|
|
|
|
-++ break;
|
|
|
|
-++ offs += blocksize;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ if (offs >= chipsize) {
|
|
|
|
-++ offs = chipsize - blocksize;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ ra_nand_bbt_set(ra, (unsigned int)offs>>ra->erase_shift, BBT_TAG_RES); // tag bbt only, instead of update badblockpos of flash.
|
|
|
|
-++ return (offs >> ra->page_shift);
|
|
|
|
-++}
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * nand_erase_nand - [Internal] erase block(s)
|
|
|
|
-++ * @mtd: MTD device structure
|
|
|
|
-++ * @instr: erase instruction
|
|
|
|
-++ * @allowbbt: allow erasing the bbt area
|
|
|
|
-++ *
|
|
|
|
-++ * Erase one ore more blocks
|
|
|
|
-++ */
|
|
|
|
-++static int _nand_erase_nand(struct ra_nand_chip *ra, struct erase_info *instr)
|
|
|
|
-++{
|
|
|
|
-++ int page, len, status, ret, state;
|
|
|
|
-++ unsigned int addr, blocksize = 1<<ra->erase_shift;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: start:%x, len:%x \n", __func__,
|
|
|
|
-++ (unsigned int)instr->addr, (unsigned int)instr->len);
|
|
|
|
-++
|
|
|
|
-++//#define BLOCK_ALIGNED(a) ((a) & (blocksize - 1)) // already defined
|
|
|
|
-++
|
|
|
|
-++ if (BLOCK_ALIGNED(instr->addr) || BLOCK_ALIGNED(instr->len)) {
|
|
|
|
-++ ra_dbg("%s: erase block not aligned, addr:%x len:%x\n", __func__, instr->addr, instr->len);
|
|
|
|
-++ return -EINVAL;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ instr->fail_addr = 0xffffffff;
|
|
|
|
-++
|
|
|
|
-++ len = instr->len;
|
|
|
|
-++ addr = instr->addr;
|
|
|
|
-++ state = MTD_ERASING;
|
|
|
|
-++
|
|
|
|
-++ while (len) {
|
|
|
|
-++
|
|
|
|
-++ page = (int)(addr >> ra->page_shift);
|
|
|
|
-++
|
|
|
|
-++ /* select device and check wp */
|
|
|
|
-++ if (nfc_enable_chip(ra, addr, 0)) {
|
|
|
|
-++ printk("%s: nand is write protected \n", __func__);
|
|
|
|
-++ state = MTD_ERASE_FAILED;
|
|
|
|
-++ goto erase_exit;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ /* if we have a bad block, we do not erase bad blocks */
|
|
|
|
-++ if (nand_block_checkbad(ra, addr)) {
|
|
|
|
-++ printk(KERN_WARNING "nand_erase: attempt to erase a "
|
|
|
|
-++ "bad block at 0x%08x\n", addr);
|
|
|
|
-++ state = MTD_ERASE_FAILED;
|
|
|
|
-++ goto erase_exit;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ /*
|
|
|
|
-++ * Invalidate the page cache, if we erase the block which
|
|
|
|
-++ * contains the current cached page
|
|
|
|
-++ */
|
|
|
|
-++ if (BLOCK_ALIGNED(addr) == BLOCK_ALIGNED(ra->buffers_page << ra->page_shift))
|
|
|
|
-++ ra->buffers_page = -1;
|
|
|
|
-++
|
|
|
|
-++ status = nfc_erase_block(ra, page);
|
|
|
|
-++ /* See if block erase succeeded */
|
|
|
|
-++ if (status) {
|
|
|
|
-++ printk("%s: failed erase, page 0x%08x\n", __func__, page);
|
|
|
|
-++ state = MTD_ERASE_FAILED;
|
|
|
|
-++ instr->fail_addr = (page << ra->page_shift);
|
|
|
|
-++ goto erase_exit;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ /* Increment page address and decrement length */
|
|
|
|
-++ len -= blocksize;
|
|
|
|
-++ addr += blocksize;
|
|
|
|
-++
|
|
|
|
-++ }
|
|
|
|
-++ state = MTD_ERASE_DONE;
|
|
|
|
-++
|
|
|
|
-++erase_exit:
|
|
|
|
-++
|
|
|
|
-++ ret = ((state == MTD_ERASE_DONE) ? 0 : -EIO);
|
|
|
|
-++
|
|
|
|
-++ if (ret) {
|
|
|
|
-++ ra_nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_BAD);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ /* Return more or less happy */
|
|
|
|
-++ return ret;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++nand_write_oob_buf(struct ra_nand_chip *ra, uint8_t *buf, uint8_t *oob, size_t size,
|
|
|
|
-++ int mode, int ooboffs)
|
|
|
|
-++{
|
|
|
|
-++ size_t oobsize = 1<<ra->oob_shift;
|
|
|
|
-++ struct nand_oobfree *free;
|
|
|
|
-++ uint32_t woffs = ooboffs;
|
|
|
|
-++ int retsize = 0;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: size:%x, mode:%x, offs:%x \n", __func__, size, mode, ooboffs);
|
|
|
|
-++
|
|
|
|
-++ switch(mode) {
|
|
|
|
-++ case MTD_OPS_PLACE_OOB:
|
|
|
|
-++ case MTD_OPS_RAW:
|
|
|
|
-++ if (ooboffs > oobsize)
|
|
|
|
-++ return -1;
|
|
|
|
-++
|
|
|
|
-++ size = min(size, oobsize - ooboffs);
|
|
|
|
-++ memcpy(buf + ooboffs, oob, size);
|
|
|
|
-++ retsize = size;
|
|
|
|
-++ break;
|
|
|
|
-++
|
|
|
|
-++ case MTD_OPS_AUTO_OOB:
|
|
|
|
-++ if (ooboffs > ra->oob->oobavail)
|
|
|
|
-++ return -1;
|
|
|
|
-++
|
|
|
|
-++ while (size) {
|
|
|
|
-++ for(free = ra->oob->oobfree; free->length && size; free++) {
|
|
|
|
-++ int wlen = free->length - woffs;
|
|
|
|
-++ int bytes = 0;
|
|
|
|
-++
|
|
|
|
-++ /* Write request not from offset 0 ? */
|
|
|
|
-++ if (wlen <= 0) {
|
|
|
|
-++ woffs = -wlen;
|
|
|
|
-++ continue;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ bytes = min_t(size_t, size, wlen);
|
|
|
|
-++ memcpy (buf + free->offset + woffs, oob, bytes);
|
|
|
|
-++ woffs = 0;
|
|
|
|
-++ oob += bytes;
|
|
|
|
-++ size -= bytes;
|
|
|
|
-++ retsize += bytes;
|
|
|
|
-++ }
|
|
|
|
-++ buf += oobsize;
|
|
|
|
-++ }
|
|
|
|
-++ break;
|
|
|
|
-++
|
|
|
|
-++ default:
|
|
|
|
-++ BUG();
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return retsize;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int nand_read_oob_buf(struct ra_nand_chip *ra, uint8_t *oob, size_t size,
|
|
|
|
-++ int mode, int ooboffs)
|
|
|
|
-++{
|
|
|
|
-++ size_t oobsize = 1<<ra->oob_shift;
|
|
|
|
-++ uint8_t *buf = ra->buffers + (1<<ra->page_shift);
|
|
|
|
-++ int retsize=0;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: size:%x, mode:%x, offs:%x \n", __func__, size, mode, ooboffs);
|
|
|
|
-++
|
|
|
|
-++ switch(mode) {
|
|
|
|
-++ case MTD_OPS_PLACE_OOB:
|
|
|
|
-++ case MTD_OPS_RAW:
|
|
|
|
-++ if (ooboffs > oobsize)
|
|
|
|
-++ return -1;
|
|
|
|
-++
|
|
|
|
-++ size = min(size, oobsize - ooboffs);
|
|
|
|
-++ memcpy(oob, buf + ooboffs, size);
|
|
|
|
-++ return size;
|
|
|
|
-++
|
|
|
|
-++ case MTD_OPS_AUTO_OOB: {
|
|
|
|
-++ struct nand_oobfree *free;
|
|
|
|
-++ uint32_t woffs = ooboffs;
|
|
|
|
-++
|
|
|
|
-++ if (ooboffs > ra->oob->oobavail)
|
|
|
|
-++ return -1;
|
|
|
|
-++
|
|
|
|
-++ size = min(size, ra->oob->oobavail - ooboffs);
|
|
|
|
-++ for(free = ra->oob->oobfree; free->length && size; free++) {
|
|
|
|
-++ int wlen = free->length - woffs;
|
|
|
|
-++ int bytes = 0;
|
|
|
|
-++
|
|
|
|
-++ /* Write request not from offset 0 ? */
|
|
|
|
-++ if (wlen <= 0) {
|
|
|
|
-++ woffs = -wlen;
|
|
|
|
-++ continue;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ bytes = min_t(size_t, size, wlen);
|
|
|
|
-++ memcpy (oob, buf + free->offset + woffs, bytes);
|
|
|
|
-++ woffs = 0;
|
|
|
|
-++ oob += bytes;
|
|
|
|
-++ size -= bytes;
|
|
|
|
-++ retsize += bytes;
|
|
|
|
-++ }
|
|
|
|
-++ return retsize;
|
|
|
|
-++ }
|
|
|
|
-++ default:
|
|
|
|
-++ BUG();
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return -1;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * nand_do_write_ops - [Internal] NAND write with ECC
|
|
|
|
-++ * @mtd: MTD device structure
|
|
|
|
-++ * @to: offset to write to
|
|
|
|
-++ * @ops: oob operations description structure
|
|
|
|
-++ *
|
|
|
|
-++ * NAND write with ECC
|
|
|
|
-++ */
|
|
|
|
-++static int nand_do_write_ops(struct ra_nand_chip *ra, loff_t to,
|
|
|
|
-++ struct mtd_oob_ops *ops)
|
|
|
|
-++{
|
|
|
|
-++ int page;
|
|
|
|
-++ uint32_t datalen = ops->len;
|
|
|
|
-++ uint32_t ooblen = ops->ooblen;
|
|
|
|
-++ uint8_t *oob = ops->oobbuf;
|
|
|
|
-++ uint8_t *data = ops->datbuf;
|
|
|
|
-++ int pagesize = (1<<ra->page_shift);
|
|
|
|
-++ int pagemask = (pagesize -1);
|
|
|
|
-++ int oobsize = 1<<ra->oob_shift;
|
|
|
|
-++ loff_t addr = to;
|
|
|
|
-++ //int i = 0; //for ra_dbg only
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: to:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x oobmode:%x \n",
|
|
|
|
-++ __func__, (unsigned int)to, data, oob, datalen, ooblen, ops->ooboffs, ops->mode);
|
|
|
|
-++
|
|
|
|
-++ ops->retlen = 0;
|
|
|
|
-++ ops->oobretlen = 0;
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++ /* Invalidate the page cache, when we write to the cached page */
|
|
|
|
-++ ra->buffers_page = -1;
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++ if (data ==0)
|
|
|
|
-++ datalen = 0;
|
|
|
|
-++
|
|
|
|
-++ // oob sequential (burst) write
|
|
|
|
-++ if (datalen == 0 && ooblen) {
|
|
|
|
-++ int len = ((ooblen + ops->ooboffs) + (ra->oob->oobavail - 1)) / ra->oob->oobavail * oobsize;
|
|
|
|
-++
|
|
|
|
-++ /* select chip, and check if it is write protected */
|
|
|
|
-++ if (nfc_enable_chip(ra, addr, 0))
|
|
|
|
-++ return -EIO;
|
|
|
|
-++
|
|
|
|
-++ //FIXME, need sanity check of block boundary
|
|
|
|
-++ page = (int)((to & ((1<<ra->chip_shift)-1)) >> ra->page_shift); //chip boundary
|
|
|
|
-++ memset(ra->buffers, 0x0ff, pagesize);
|
|
|
|
-++ //fixme, should we reserve the original content?
|
|
|
|
-++ if (ops->mode == MTD_OPS_AUTO_OOB) {
|
|
|
|
-++ nfc_read_oob(ra, page, 0, ra->buffers, len, FLAG_NONE);
|
|
|
|
-++ }
|
|
|
|
-++ //prepare buffers
|
|
|
|
-++ if (ooblen != 8)
|
|
|
|
-++ {
|
|
|
|
-++ nand_write_oob_buf(ra, ra->buffers, oob, ooblen, ops->mode, ops->ooboffs);
|
|
|
|
-++ // write out buffer to chip
|
|
|
|
-++ nfc_write_oob(ra, page, 0, ra->buffers, len, FLAG_USE_GDMA);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ ops->oobretlen = ooblen;
|
|
|
|
-++ ooblen = 0;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ // data sequential (burst) write
|
|
|
|
-++ if (datalen && ooblen == 0) {
|
|
|
|
-++ // ranfc can not support write_data_burst, since hw-ecc and fifo constraints..
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ // page write
|
|
|
|
-++ while(datalen || ooblen) {
|
|
|
|
-++ int len;
|
|
|
|
-++ int ret;
|
|
|
|
-++ int offs;
|
|
|
|
-++ int ecc_en = 0;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s (%d): addr:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x \n",
|
|
|
|
-++ __func__, i++, (unsigned int)addr, data, oob, datalen, ooblen, ops->ooboffs);
|
|
|
|
-++
|
|
|
|
-++ page = (int)((addr & ((1<<ra->chip_shift)-1)) >> ra->page_shift); //chip boundary
|
|
|
|
-++
|
|
|
|
-++ /* select chip, and check if it is write protected */
|
|
|
|
-++ if (nfc_enable_chip(ra, addr, 0))
|
|
|
|
-++ return -EIO;
|
|
|
|
-++
|
|
|
|
-++ // oob write
|
|
|
|
-++ if (ops->mode == MTD_OPS_AUTO_OOB) {
|
|
|
|
-++ //fixme, this path is not yet varified
|
|
|
|
-++ nfc_read_oob(ra, page, 0, ra->buffers + pagesize, oobsize, FLAG_NONE);
|
|
|
|
-++ }
|
|
|
|
-++ if (oob && ooblen > 0) {
|
|
|
|
-++ len = nand_write_oob_buf(ra, ra->buffers + pagesize, oob, ooblen, ops->mode, ops->ooboffs);
|
|
|
|
-++ if (len < 0)
|
|
|
|
-++ return -EINVAL;
|
|
|
|
-++
|
|
|
|
-++ oob += len;
|
|
|
|
-++ ops->oobretlen += len;
|
|
|
|
-++ ooblen -= len;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ // data write
|
|
|
|
-++ offs = addr & pagemask;
|
|
|
|
-++ len = min_t(size_t, datalen, pagesize - offs);
|
|
|
|
-++ if (data && len > 0) {
|
|
|
|
-++ memcpy(ra->buffers + offs, data, len); // we can not sure ops->buf wether is DMA-able.
|
|
|
|
-++
|
|
|
|
-++ data += len;
|
|
|
|
-++ datalen -= len;
|
|
|
|
-++ ops->retlen += len;
|
|
|
|
-++
|
|
|
|
-++ ecc_en = FLAG_ECC_EN;
|
|
|
|
-++ }
|
|
|
|
-++ ret = nfc_write_page(ra, ra->buffers, page, FLAG_USE_GDMA | FLAG_VERIFY |
|
|
|
|
-++ ((ops->mode == MTD_OPS_RAW || ops->mode == MTD_OPS_PLACE_OOB) ? 0 : ecc_en ));
|
|
|
|
-++ if (ret) {
|
|
|
|
-++ ra_nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_BAD);
|
|
|
|
-++ return ret;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ ra_nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_GOOD);
|
|
|
|
-++
|
|
|
|
-++ addr = (page+1) << ra->page_shift;
|
|
|
|
-++
|
|
|
|
-++ }
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/**
|
|
|
|
-++ * nand_do_read_ops - [Internal] Read data with ECC
|
|
|
|
-++ *
|
|
|
|
-++ * @mtd: MTD device structure
|
|
|
|
-++ * @from: offset to read from
|
|
|
|
-++ * @ops: oob ops structure
|
|
|
|
-++ *
|
|
|
|
-++ * Internal function. Called with chip held.
|
|
|
|
-++ */
|
|
|
|
-++static int nand_do_read_ops(struct ra_nand_chip *ra, loff_t from,
|
|
|
|
-++ struct mtd_oob_ops *ops)
|
|
|
|
-++{
|
|
|
|
-++ int page;
|
|
|
|
-++ uint32_t datalen = ops->len;
|
|
|
|
-++ uint32_t ooblen = ops->ooblen;
|
|
|
|
-++ uint8_t *oob = ops->oobbuf;
|
|
|
|
-++ uint8_t *data = ops->datbuf;
|
|
|
|
-++ int pagesize = (1<<ra->page_shift);
|
|
|
|
-++ int pagemask = (pagesize -1);
|
|
|
|
-++ loff_t addr = from;
|
|
|
|
-++ //int i = 0; //for ra_dbg only
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: addr:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x \n",
|
|
|
|
-++ __func__, (unsigned int)addr, data, oob, datalen, ooblen, ops->ooboffs);
|
|
|
|
-++
|
|
|
|
-++ ops->retlen = 0;
|
|
|
|
-++ ops->oobretlen = 0;
|
|
|
|
-++ if (data == 0)
|
|
|
|
-++ datalen = 0;
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++ while(datalen || ooblen) {
|
|
|
|
-++ int len;
|
|
|
|
-++ int ret;
|
|
|
|
-++ int offs;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s (%d): addr:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x \n",
|
|
|
|
-++ __func__, i++, (unsigned int)addr, data, oob, datalen, ooblen, ops->ooboffs);
|
|
|
|
-++ /* select chip */
|
|
|
|
-++ if (nfc_enable_chip(ra, addr, 1) < 0)
|
|
|
|
-++ return -EIO;
|
|
|
|
-++
|
|
|
|
-++ page = (int)((addr & ((1<<ra->chip_shift)-1)) >> ra->page_shift);
|
|
|
|
-++
|
|
|
|
-++ ret = nfc_read_page(ra, ra->buffers, page, FLAG_VERIFY |
|
|
|
|
-++ ((ops->mode == MTD_OPS_RAW || ops->mode == MTD_OPS_PLACE_OOB) ? 0: FLAG_ECC_EN ));
|
|
|
|
-++ //FIXME, something strange here, some page needs 2 more tries to guarantee read success.
|
|
|
|
-++ if (ret) {
|
|
|
|
-++ printk("read again:\n");
|
|
|
|
-++ ret = nfc_read_page(ra, ra->buffers, page, FLAG_VERIFY |
|
|
|
|
-++ ((ops->mode == MTD_OPS_RAW || ops->mode == MTD_OPS_PLACE_OOB) ? 0: FLAG_ECC_EN ));
|
|
|
|
-++
|
|
|
|
-++ if (ret) {
|
|
|
|
-++ printk("read again fail \n");
|
|
|
|
-++ ra_nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_BAD);
|
|
|
|
-++ if ((ret != -EUCLEAN) && (ret != -EBADMSG)) {
|
|
|
|
-++ return ret;
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ /* ecc verification fail, but data need to be returned. */
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ printk(" read agian susccess \n");
|
|
|
|
-++ }
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ // oob read
|
|
|
|
-++ if (oob && ooblen > 0) {
|
|
|
|
-++ len = nand_read_oob_buf(ra, oob, ooblen, ops->mode, ops->ooboffs);
|
|
|
|
-++ if (len < 0) {
|
|
|
|
-++ printk("nand_read_oob_buf: fail return %x \n", len);
|
|
|
|
-++ return -EINVAL;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ oob += len;
|
|
|
|
-++ ops->oobretlen += len;
|
|
|
|
-++ ooblen -= len;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ // data read
|
|
|
|
-++ offs = addr & pagemask;
|
|
|
|
-++ len = min_t(size_t, datalen, pagesize - offs);
|
|
|
|
-++ if (data && len > 0) {
|
|
|
|
-++ memcpy(data, ra->buffers + offs, len); // we can not sure ops->buf wether is DMA-able.
|
|
|
|
-++
|
|
|
|
-++ data += len;
|
|
|
|
-++ datalen -= len;
|
|
|
|
-++ ops->retlen += len;
|
|
|
|
-++ if (ret)
|
|
|
|
-++ return ret;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++ ra_nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_GOOD);
|
|
|
|
-++ // address go further to next page, instead of increasing of length of write. This avoids some special cases wrong.
|
|
|
|
-++ addr = (page+1) << ra->page_shift;
|
|
|
|
-++ }
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++ramtd_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|
|
|
-++{
|
|
|
|
-++ struct ra_nand_chip *ra = (struct ra_nand_chip *)mtd->priv;
|
|
|
|
-++ int ret;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: start:%x, len:%x \n", __func__,
|
|
|
|
-++ (unsigned int)instr->addr, (unsigned int)instr->len);
|
|
|
|
-++
|
|
|
|
-++ nand_get_device(ra, FL_ERASING);
|
|
|
|
-++ ret = _nand_erase_nand((struct ra_nand_chip *)mtd->priv, instr);
|
|
|
|
-++ nand_release_device(ra);
|
|
|
|
-++
|
|
|
|
-++ return ret;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++ramtd_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
|
-++ size_t *retlen, const uint8_t *buf)
|
|
|
|
-++{
|
|
|
|
-++ struct ra_nand_chip *ra = mtd->priv;
|
|
|
|
-++ struct mtd_oob_ops ops;
|
|
|
|
-++ int ret;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: to 0x%x len=0x%x\n", __func__, to, len);
|
|
|
|
-++
|
|
|
|
-++ if ((to + len) > mtd->size)
|
|
|
|
-++ return -EINVAL;
|
|
|
|
-++
|
|
|
|
-++ if (!len)
|
|
|
|
-++ return 0;
|
|
|
|
-++
|
|
|
|
-++ nand_get_device(ra, FL_WRITING);
|
|
|
|
-++
|
|
|
|
-++ memset(&ops, 0, sizeof(ops));
|
|
|
|
-++ ops.len = len;
|
|
|
|
-++ ops.datbuf = (uint8_t *)buf;
|
|
|
|
-++ ops.oobbuf = NULL;
|
|
|
|
-++ ops.mode = MTD_OPS_AUTO_OOB;
|
|
|
|
-++
|
|
|
|
-++ ret = nand_do_write_ops(ra, to, &ops);
|
|
|
|
-++
|
|
|
|
-++ *retlen = ops.retlen;
|
|
|
|
-++
|
|
|
|
-++ nand_release_device(ra);
|
|
|
|
-++
|
|
|
|
-++ return ret;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++ramtd_nand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|
|
|
-++ size_t *retlen, uint8_t *buf)
|
|
|
|
-++{
|
|
|
|
-++ struct ra_nand_chip *ra = mtd->priv;
|
|
|
|
-++ int ret;
|
|
|
|
-++ struct mtd_oob_ops ops;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: mtd:%p from:%x, len:%x, buf:%p \n", __func__, mtd, (unsigned int)from, len, buf);
|
|
|
|
-++
|
|
|
|
-++ /* Do not allow reads past end of device */
|
|
|
|
-++ if ((from + len) > mtd->size)
|
|
|
|
-++ return -EINVAL;
|
|
|
|
-++ if (!len)
|
|
|
|
-++ return 0;
|
|
|
|
-++
|
|
|
|
-++ nand_get_device(ra, FL_READING);
|
|
|
|
-++
|
|
|
|
-++ memset(&ops, 0, sizeof(ops));
|
|
|
|
-++ ops.len = len;
|
|
|
|
-++ ops.datbuf = buf;
|
|
|
|
-++ ops.oobbuf = NULL;
|
|
|
|
-++ ops.mode = MTD_OPS_AUTO_OOB;
|
|
|
|
-++
|
|
|
|
-++ ret = nand_do_read_ops(ra, from, &ops);
|
|
|
|
-++
|
|
|
|
-++ *retlen = ops.retlen;
|
|
|
|
-++
|
|
|
|
-++ nand_release_device(ra);
|
|
|
|
-++
|
|
|
|
-++ return ret;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++ramtd_nand_readoob(struct mtd_info *mtd, loff_t from,
|
|
|
|
-++ struct mtd_oob_ops *ops)
|
|
|
|
-++{
|
|
|
|
-++ struct ra_nand_chip *ra = mtd->priv;
|
|
|
|
-++ int ret;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: \n", __func__);
|
|
|
|
-++
|
|
|
|
-++ nand_get_device(ra, FL_READING);
|
|
|
|
-++
|
|
|
|
-++ ret = nand_do_read_ops(ra, from, ops);
|
|
|
|
-++
|
|
|
|
-++ nand_release_device(ra);
|
|
|
|
-++
|
|
|
|
-++ return ret;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++ramtd_nand_writeoob(struct mtd_info *mtd, loff_t to,
|
|
|
|
-++ struct mtd_oob_ops *ops)
|
|
|
|
-++{
|
|
|
|
-++ struct ra_nand_chip *ra = mtd->priv;
|
|
|
|
-++ int ret;
|
|
|
|
-++
|
|
|
|
-++ nand_get_device(ra, FL_READING);
|
|
|
|
-++ ret = nand_do_write_ops(ra, to, ops);
|
|
|
|
-++ nand_release_device(ra);
|
|
|
|
-++
|
|
|
|
-++ return ret;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++ramtd_nand_block_isbad(struct mtd_info *mtd, loff_t offs)
|
|
|
|
-++{
|
|
|
|
-++ if (offs > mtd->size)
|
|
|
|
-++ return -EINVAL;
|
|
|
|
-++
|
|
|
|
-++ return nand_block_checkbad((struct ra_nand_chip *)mtd->priv, offs);
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++ramtd_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|
|
|
-++{
|
|
|
|
-++ struct ra_nand_chip *ra = mtd->priv;
|
|
|
|
-++ int ret;
|
|
|
|
-++
|
|
|
|
-++ ra_dbg("%s: \n", __func__);
|
|
|
|
-++ nand_get_device(ra, FL_WRITING);
|
|
|
|
-++ ret = nand_block_markbad(ra, ofs);
|
|
|
|
-++ nand_release_device(ra);
|
|
|
|
-++
|
|
|
|
-++ return ret;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++// 1-bit error detection
|
|
|
|
-++static int one_bit_correction(char *ecc1, char *ecc2, int *bytes, int *bits)
|
|
|
|
-++{
|
|
|
|
-++ // check if ecc and expected are all valid
|
|
|
|
-++ char *p, nibble, crumb;
|
|
|
|
-++ int i, xor, iecc1 = 0, iecc2 = 0;
|
|
|
|
-++
|
|
|
|
-++ printk("correction : %x %x %x\n", ecc1[0], ecc1[1], ecc1[2]);
|
|
|
|
-++ printk("correction : %x %x %x\n", ecc2[0], ecc2[1], ecc2[2]);
|
|
|
|
-++
|
|
|
|
-++ p = (char *)ecc1;
|
|
|
|
-++ for (i = 0; i < CONFIG_ECC_BYTES; i++)
|
|
|
|
-++ {
|
|
|
|
-++ nibble = *(p+i) & 0xf;
|
|
|
|
-++ if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
|
|
|
|
-++ (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
|
|
|
|
-++ return -1;
|
|
|
|
-++ nibble = ((*(p+i)) >> 4) & 0xf;
|
|
|
|
-++ if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
|
|
|
|
-++ (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ p = (char *)ecc2;
|
|
|
|
-++ for (i = 0; i < CONFIG_ECC_BYTES; i++)
|
|
|
|
-++ {
|
|
|
|
-++ nibble = *(p+i) & 0xf;
|
|
|
|
-++ if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
|
|
|
|
-++ (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
|
|
|
|
-++ return -1;
|
|
|
|
-++ nibble = ((*(p+i)) >> 4) & 0xf;
|
|
|
|
-++ if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
|
|
|
|
-++ (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
|
|
|
|
-++ return -1;
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ memcpy(&iecc1, ecc1, 3);
|
|
|
|
-++ memcpy(&iecc2, ecc2, 3);
|
|
|
|
-++
|
|
|
|
-++ xor = iecc1 ^ iecc2;
|
|
|
|
-++ printk("xor = %x (%x %x)\n", xor, iecc1, iecc2);
|
|
|
|
-++
|
|
|
|
-++ *bytes = 0;
|
|
|
|
-++ for (i = 0; i < 9; i++)
|
|
|
|
-++ {
|
|
|
|
-++ crumb = (xor >> (2*i)) & 0x3;
|
|
|
|
-++ if ((crumb == 0x0) || (crumb == 0x3))
|
|
|
|
-++ return -1;
|
|
|
|
-++ if (crumb == 0x2)
|
|
|
|
-++ *bytes += (1 << i);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ *bits = 0;
|
|
|
|
-++ for (i = 0; i < 3; i++)
|
|
|
|
-++ {
|
|
|
|
-++ crumb = (xor >> (18 + 2*i)) & 0x3;
|
|
|
|
-++ if ((crumb == 0x0) || (crumb == 0x3))
|
|
|
|
-++ return -1;
|
|
|
|
-++ if (crumb == 0x2)
|
|
|
|
-++ *bits += (1 << i);
|
|
|
|
-++ }
|
|
|
|
-++
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++/************************************************************
|
|
|
|
-++ * the init/exit section.
|
|
|
|
-++ */
|
|
|
|
-++
|
|
|
|
-++static struct nand_ecclayout ra_oob_layout = {
|
|
|
|
-++ .eccbytes = CONFIG_ECC_BYTES,
|
|
|
|
-++ .eccpos = {5, 6, 7},
|
|
|
|
-++ .oobfree = {
|
|
|
|
-++ {.offset = 0, .length = 4},
|
|
|
|
-++ {.offset = 8, .length = 8},
|
|
|
|
-++ {.offset = 0, .length = 0}
|
|
|
|
-++ },
|
|
|
|
-++#define RA_CHIP_OOB_AVAIL (4+8)
|
|
|
|
-++ .oobavail = RA_CHIP_OOB_AVAIL,
|
|
|
|
-++ // 5th byte is bad-block flag.
|
|
|
|
-++};
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++mtk_nand_probe(struct platform_device *pdev)
|
|
|
|
-++{
|
|
|
|
-++ struct mtd_part_parser_data ppdata;
|
|
|
|
-++ struct ra_nand_chip *ra;
|
|
|
|
-++ int alloc_size, bbt_size, buffers_size, reg, err;
|
|
|
|
-++ unsigned char chip_mode = 12;
|
|
|
|
-++
|
|
|
|
-++ /* if(ra_check_flash_type()!=BOOT_FROM_NAND) {
|
|
|
|
-++ return 0;
|
|
|
|
-++ }*/
|
|
|
|
-++
|
|
|
|
-++ //FIXME: config 512 or 2048-byte page according to HWCONF
|
|
|
|
-++#if defined (CONFIG_SOC_MT7620)
|
|
|
|
-++ ra_outl(RALINK_SYSCTL_BASE+0x60, ra_inl(RALINK_SYSCTL_BASE+0x60) & ~(0x3<<18));
|
|
|
|
-++ reg = ra_inl(RALINK_SYSCTL_BASE+0x10);
|
|
|
|
-++ chip_mode = (reg & 0x0F);
|
|
|
|
-++ if((chip_mode==1)||(chip_mode==11)) {
|
|
|
|
-++ ra_or(NFC_CONF1, 1);
|
|
|
|
-++ is_nand_page_2048 = 1;
|
|
|
|
-++ nand_addrlen = ((chip_mode!=11) ? 4 : 5);
|
|
|
|
-++ printk("!!! nand page size = 2048, addr len=%d\n", nand_addrlen);
|
|
|
|
-++ }
|
|
|
|
-++ else {
|
|
|
|
-++ ra_and(NFC_CONF1, ~1);
|
|
|
|
-++ is_nand_page_2048 = 0;
|
|
|
|
-++ nand_addrlen = ((chip_mode!=10) ? 3 : 4);
|
|
|
|
-++ printk("!!! nand page size = 512, addr len=%d\n", nand_addrlen);
|
|
|
|
-++ }
|
|
|
|
-++#else
|
|
|
|
-++ is_nand_page_2048 = 0;
|
|
|
|
-++ nand_addrlen = 3;
|
|
|
|
-++ printk("!!! nand page size = 512, addr len=%d\n", nand_addrlen);
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++#if defined (CONFIG_SOC_MT7620)
|
|
|
|
-++ //config ECC location
|
|
|
|
-++ ra_and(NFC_CONF1, 0xfff000ff);
|
|
|
|
-++ ra_or(NFC_CONF1, ((CONFIG_ECC_OFFSET + 2) << 16) +
|
|
|
|
-++ ((CONFIG_ECC_OFFSET + 1) << 12) +
|
|
|
|
-++ (CONFIG_ECC_OFFSET << 8));
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++#define ALIGNE_16(a) (((unsigned long)(a)+15) & ~15)
|
|
|
|
-++ buffers_size = ALIGNE_16((1<<CONFIG_PAGE_SIZE_BIT) + (1<<CONFIG_OOBSIZE_PER_PAGE_BIT)); //ra->buffers
|
|
|
|
-++ bbt_size = BBTTAG_BITS * (1<<(CONFIG_CHIP_SIZE_BIT - (CONFIG_PAGE_SIZE_BIT + CONFIG_NUMPAGE_PER_BLOCK_BIT))) / 8; //ra->bbt
|
|
|
|
-++ bbt_size = ALIGNE_16(bbt_size);
|
|
|
|
-++
|
|
|
|
-++ alloc_size = buffers_size + bbt_size;
|
|
|
|
-++ alloc_size += buffers_size; //for ra->readback_buffers
|
|
|
|
-++ alloc_size += sizeof(*ra);
|
|
|
|
-++ alloc_size += sizeof(*ranfc_mtd);
|
|
|
|
-++
|
|
|
|
-++ //make sure gpio-0 is input
|
|
|
|
-++ ra_outl(RALINK_PIO_BASE+0x24, ra_inl(RALINK_PIO_BASE+0x24) & ~0x01);
|
|
|
|
-++
|
|
|
|
-++ ra = (struct ra_nand_chip *)kzalloc(alloc_size, GFP_KERNEL | GFP_DMA);
|
|
|
|
-++ if (!ra) {
|
|
|
|
-++ printk("%s: mem alloc fail \n", __func__);
|
|
|
|
-++ return -ENOMEM;
|
|
|
|
-++ }
|
|
|
|
-++ memset(ra, 0, alloc_size);
|
|
|
|
-++
|
|
|
|
-++ //dynamic
|
|
|
|
-++ ra->buffers = (char *)((char *)ra + sizeof(*ra));
|
|
|
|
-++ ra->readback_buffers = ra->buffers + buffers_size;
|
|
|
|
-++ ra->bbt = ra->readback_buffers + buffers_size;
|
|
|
|
-++ ranfc_mtd = (struct mtd_info *)(ra->bbt + bbt_size);
|
|
|
|
-++
|
|
|
|
-++ //static
|
|
|
|
-++ ra->numchips = CONFIG_NUMCHIPS;
|
|
|
|
-++ ra->chip_shift = CONFIG_CHIP_SIZE_BIT;
|
|
|
|
-++ ra->page_shift = CONFIG_PAGE_SIZE_BIT;
|
|
|
|
-++ ra->oob_shift = CONFIG_OOBSIZE_PER_PAGE_BIT;
|
|
|
|
-++ ra->erase_shift = (CONFIG_PAGE_SIZE_BIT + CONFIG_NUMPAGE_PER_BLOCK_BIT);
|
|
|
|
-++ ra->badblockpos = CONFIG_BAD_BLOCK_POS;
|
|
|
|
-++ ra_oob_layout.eccpos[0] = CONFIG_ECC_OFFSET;
|
|
|
|
-++ ra_oob_layout.eccpos[1] = CONFIG_ECC_OFFSET + 1;
|
|
|
|
-++ ra_oob_layout.eccpos[2] = CONFIG_ECC_OFFSET + 2;
|
|
|
|
-++ ra->oob = &ra_oob_layout;
|
|
|
|
-++ ra->buffers_page = -1;
|
|
|
|
-++
|
|
|
|
-++#if defined (WORKAROUND_RX_BUF_OV)
|
|
|
|
-++ if (ranfc_verify) {
|
|
|
|
-++ ra->sandbox_page = nand_bbt_find_sandbox(ra);
|
|
|
|
-++ }
|
|
|
|
-++#endif
|
|
|
|
-++ ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x01); //set wp to high
|
|
|
|
-++ nfc_all_reset();
|
|
|
|
-++
|
|
|
|
-++ ranfc_mtd->type = MTD_NANDFLASH;
|
|
|
|
-++ ranfc_mtd->flags = MTD_CAP_NANDFLASH;
|
|
|
|
-++ ranfc_mtd->size = CONFIG_NUMCHIPS * CFG_CHIPSIZE;
|
|
|
|
-++ ranfc_mtd->erasesize = CFG_BLOCKSIZE;
|
|
|
|
-++ ranfc_mtd->writesize = CFG_PAGESIZE;
|
|
|
|
-++ ranfc_mtd->writebufsize = ranfc_mtd->writesize;
|
|
|
|
-++ ranfc_mtd->oobsize = CFG_PAGE_OOBSIZE;
|
|
|
|
-++ ranfc_mtd->oobavail = RA_CHIP_OOB_AVAIL;
|
|
|
|
-++ ranfc_mtd->name = "ra_nfc";
|
|
|
|
-++ //ranfc_mtd->index
|
|
|
|
-++ //ranfc_mtd->ecclayout = &ra_oob_layout;
|
|
|
|
-++ //ranfc_mtd->numberaseregions
|
|
|
|
-++ //ranfc_mtd->eraseregions
|
|
|
|
-++ //ranfc_mtd->bansize
|
|
|
|
-++ ranfc_mtd->_erase = ramtd_nand_erase;
|
|
|
|
-++ //ranfc_mtd->point
|
|
|
|
-++ //ranfc_mtd->unpoint
|
|
|
|
-++ ranfc_mtd->_read = ramtd_nand_read;
|
|
|
|
-++ ranfc_mtd->_write = ramtd_nand_write;
|
|
|
|
-++ //ranfc_mtd->_read_oob = ramtd_nand_readoob;
|
|
|
|
-++ //ranfc_mtd->_write_oob = ramtd_nand_writeoob;
|
|
|
|
-++ //ranfc_mtd->get_fact_prot_info; ranfc_mtd->read_fact_prot_reg;
|
|
|
|
-++ //ranfc_mtd->get_user_prot_info; ranfc_mtd->read_user_prot_reg;
|
|
|
|
-++ //ranfc_mtd->write_user_prot_reg; ranfc_mtd->lock_user_prot_reg;
|
|
|
|
-++ //ranfc_mtd->writev; ranfc_mtd->sync; ranfc_mtd->lock; ranfc_mtd->unlock; ranfc_mtd->suspend; ranfc_mtd->resume;
|
|
|
|
-++ ranfc_mtd->_block_isbad = ramtd_nand_block_isbad;
|
|
|
|
-++ ranfc_mtd->_block_markbad = ramtd_nand_block_markbad;
|
|
|
|
-++ //ranfc_mtd->reboot_notifier
|
|
|
|
-++ //ranfc_mtd->ecc_stats;
|
|
|
|
-++ // subpage_sht;
|
|
|
|
-++
|
|
|
|
-++ //ranfc_mtd->get_device; ranfc_mtd->put_device
|
|
|
|
-++ ranfc_mtd->priv = ra;
|
|
|
|
-++
|
|
|
|
-++ ranfc_mtd->owner = THIS_MODULE;
|
|
|
|
-++ ra->controller = &ra->hwcontrol;
|
|
|
|
-++ mutex_init(ra->controller);
|
|
|
|
-++
|
|
|
|
-++ printk("%s: alloc %x, at %p , btt(%p, %x), ranfc_mtd:%p\n",
|
|
|
|
-++ __func__, alloc_size, ra, ra->bbt, bbt_size, ranfc_mtd);
|
|
|
|
-++
|
|
|
|
-++ mtd_set_of_node(ranfc_mtd, pdev->dev.of_node);
|
|
|
|
-++ err = mtd_device_parse_register(ranfc_mtd, mtk_probe_types,
|
|
|
|
-++ &ppdata, NULL, 0);
|
|
|
|
-++
|
|
|
|
-++ return err;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static int
|
|
|
|
-++mtk_nand_remove(struct platform_device *pdev)
|
|
|
|
-++{
|
|
|
|
-++ struct ra_nand_chip *ra;
|
|
|
|
-++
|
|
|
|
-++ if (ranfc_mtd) {
|
|
|
|
-++ ra = (struct ra_nand_chip *)ranfc_mtd->priv;
|
|
|
|
-++
|
|
|
|
-++ /* Deregister partitions */
|
|
|
|
-++ //del_mtd_partitions(ranfc_mtd);
|
|
|
|
-++ kfree(ra);
|
|
|
|
-++ }
|
|
|
|
-++ return 0;
|
|
|
|
-++}
|
|
|
|
-++
|
|
|
|
-++static const struct of_device_id mtk_nand_match[] = {
|
|
|
|
-++ { .compatible = "mtk,mt7620-nand" },
|
|
|
|
-++ {},
|
|
|
|
-++};
|
|
|
|
-++MODULE_DEVICE_TABLE(of, mtk_nand_match);
|
|
|
|
-++
|
|
|
|
-++static struct platform_driver mtk_nand_driver = {
|
|
|
|
-++ .probe = mtk_nand_probe,
|
|
|
|
-++ .remove = mtk_nand_remove,
|
|
|
|
-++ .driver = {
|
|
|
|
-++ .name = "mt7620_nand",
|
|
|
|
-++ .owner = THIS_MODULE,
|
|
|
|
-++ .of_match_table = mtk_nand_match,
|
|
|
|
-++ },
|
|
|
|
-++};
|
|
|
|
-++
|
|
|
|
-++module_platform_driver(mtk_nand_driver);
|
|
|
|
-++
|
|
|
|
-++MODULE_LICENSE("GPL");
|
|
|
|
-+--- /dev/null
|
|
|
|
-++++ b/drivers/mtd/maps/ralink_nand.h
|
|
|
|
-+@@ -0,0 +1,240 @@
|
|
|
|
-++#ifndef RT2880_NAND_H
|
|
|
|
-++#define RT2880_NAND_H
|
|
|
|
-++
|
|
|
|
-++#include <linux/mtd/mtd.h>
|
|
|
|
-++
|
|
|
|
-++#define MTD_ERASE_PENDING 0x01
|
|
|
|
-++#define MTD_ERASING 0x02
|
|
|
|
-++#define MTD_ERASE_SUSPEND 0x04
|
|
|
|
-++#define MTD_ERASE_DONE 0x08
|
|
|
|
-++#define MTD_ERASE_FAILED 0x10
|
|
|
|
-++
|
|
|
|
-++#define MTD_FAIL_ADDR_UNKNOWN -1LL
|
|
|
|
-++
|
|
|
|
-++//#include "gdma.h"
|
|
|
|
-++
|
|
|
|
-++#define RALINK_SYSCTL_BASE 0xB0000000
|
|
|
|
-++#define RALINK_PIO_BASE 0xB0000600
|
|
|
|
-++#define RALINK_NAND_CTRL_BASE 0xB0000810
|
|
|
|
-++#define CONFIG_RALINK_MT7620
|
|
|
|
-++
|
|
|
|
-++#define SKIP_BAD_BLOCK
|
|
|
|
-++//#define RANDOM_GEN_BAD_BLOCK
|
|
|
|
-++
|
|
|
|
-++#define ra_inl(addr) (*(volatile unsigned int *)(addr))
|
|
|
|
-++#define ra_outl(addr, value) (*(volatile unsigned int *)(addr) = (value))
|
|
|
|
-++#define ra_aor(addr, a_mask, o_value) ra_outl(addr, (ra_inl(addr) & (a_mask)) | (o_value))
|
|
|
|
-++#define ra_and(addr, a_mask) ra_aor(addr, a_mask, 0)
|
|
|
|
-++#define ra_or(addr, o_value) ra_aor(addr, -1, o_value)
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++#define CONFIG_NUMCHIPS 1
|
|
|
|
-++#define CONFIG_NOT_SUPPORT_WP //rt3052 has no WP signal for chip.
|
|
|
|
-++//#define CONFIG_NOT_SUPPORT_RB
|
|
|
|
-++
|
|
|
|
-++extern int is_nand_page_2048;
|
|
|
|
-++extern const unsigned int nand_size_map[2][3];
|
|
|
|
-++
|
|
|
|
-++//chip
|
|
|
|
-++// chip geometry: SAMSUNG small size 32MB.
|
|
|
|
-++#define CONFIG_CHIP_SIZE_BIT (nand_size_map[is_nand_page_2048][nand_addrlen-3]) //! (1<<NAND_SIZE_BYTE) MB
|
|
|
|
-++//#define CONFIG_CHIP_SIZE_BIT (is_nand_page_2048? 29 : 25) //! (1<<NAND_SIZE_BYTE) MB
|
|
|
|
-++#define CONFIG_PAGE_SIZE_BIT (is_nand_page_2048? 11 : 9) //! (1<<PAGE_SIZE) MB
|
|
|
|
-++//#define CONFIG_SUBPAGE_BIT 1 //! these bits will be compensate by command cycle
|
|
|
|
-++#define CONFIG_NUMPAGE_PER_BLOCK_BIT (is_nand_page_2048? 6 : 5) //! order of number of pages a block.
|
|
|
|
-++#define CONFIG_OOBSIZE_PER_PAGE_BIT (is_nand_page_2048? 6 : 4) //! byte number of oob a page.
|
|
|
|
-++#define CONFIG_BAD_BLOCK_POS (is_nand_page_2048? 0 : 4) //! offset of byte to denote bad block.
|
|
|
|
-++#define CONFIG_ECC_BYTES 3 //! ecc has 3 bytes
|
|
|
|
-++#define CONFIG_ECC_OFFSET (is_nand_page_2048? 6 : 5) //! ecc starts from offset 5.
|
|
|
|
-++
|
|
|
|
-++//this section should not be modified.
|
|
|
|
-++//#define CFG_COLUMN_ADDR_MASK ((1 << (CONFIG_PAGE_SIZE_BIT - CONFIG_SUBPAGE_BIT)) - 1)
|
|
|
|
-++//#define CFG_COLUMN_ADDR_CYCLE (((CONFIG_PAGE_SIZE_BIT - CONFIG_SUBPAGE_BIT) + 7)/8)
|
|
|
|
-++//#define CFG_ROW_ADDR_CYCLE ((CONFIG_CHIP_SIZE_BIT - CONFIG_PAGE_SIZE_BIT + 7)/8)
|
|
|
|
-++//#define CFG_ADDR_CYCLE (CFG_COLUMN_ADDR_CYCLE + CFG_ROW_ADDR_CYCLE)
|
|
|
|
-++
|
|
|
|
-++#define CFG_COLUMN_ADDR_CYCLE (is_nand_page_2048? 2 : 1)
|
|
|
|
-++#define CFG_ROW_ADDR_CYCLE (nand_addrlen - CFG_COLUMN_ADDR_CYCLE)
|
|
|
|
-++#define CFG_ADDR_CYCLE (CFG_COLUMN_ADDR_CYCLE + CFG_ROW_ADDR_CYCLE)
|
|
|
|
-++
|
|
|
|
-++#define CFG_CHIPSIZE (1 << ((CONFIG_CHIP_SIZE_BIT>=32)? 31 : CONFIG_CHIP_SIZE_BIT))
|
|
|
|
-++//#define CFG_CHIPSIZE (1 << CONFIG_CHIP_SIZE_BIT)
|
|
|
|
-++#define CFG_PAGESIZE (1 << CONFIG_PAGE_SIZE_BIT)
|
|
|
|
-++#define CFG_BLOCKSIZE (CFG_PAGESIZE << CONFIG_NUMPAGE_PER_BLOCK_BIT)
|
|
|
|
-++#define CFG_NUMPAGE (1 << (CONFIG_CHIP_SIZE_BIT - CONFIG_PAGE_SIZE_BIT))
|
|
|
|
-++#define CFG_NUMBLOCK (CFG_NUMPAGE >> CONFIG_NUMPAGE_PER_BLOCK_BIT)
|
|
|
|
-++#define CFG_BLOCK_OOBSIZE (1 << (CONFIG_OOBSIZE_PER_PAGE_BIT + CONFIG_NUMPAGE_PER_BLOCK_BIT))
|
|
|
|
-++#define CFG_PAGE_OOBSIZE (1 << CONFIG_OOBSIZE_PER_PAGE_BIT)
|
|
|
|
-++
|
|
|
|
-++#define NAND_BLOCK_ALIGN(addr) ((addr) & (CFG_BLOCKSIZE-1))
|
|
|
|
-++#define NAND_PAGE_ALIGN(addr) ((addr) & (CFG_PAGESIZE-1))
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++#define NFC_BASE RALINK_NAND_CTRL_BASE
|
|
|
|
-++#define NFC_CTRL (NFC_BASE + 0x0)
|
|
|
|
-++#define NFC_CONF (NFC_BASE + 0x4)
|
|
|
|
-++#define NFC_CMD1 (NFC_BASE + 0x8)
|
|
|
|
-++#define NFC_CMD2 (NFC_BASE + 0xc)
|
|
|
|
-++#define NFC_CMD3 (NFC_BASE + 0x10)
|
|
|
|
-++#define NFC_ADDR (NFC_BASE + 0x14)
|
|
|
|
-++#define NFC_DATA (NFC_BASE + 0x18)
|
|
|
|
-++#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
|
|
|
|
-++ defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)
|
|
|
|
-++#define NFC_ECC (NFC_BASE + 0x30)
|
|
|
|
-++#else
|
|
|
|
-++#define NFC_ECC (NFC_BASE + 0x1c)
|
|
|
|
-++#endif
|
|
|
|
-++#define NFC_STATUS (NFC_BASE + 0x20)
|
|
|
|
-++#define NFC_INT_EN (NFC_BASE + 0x24)
|
|
|
|
-++#define NFC_INT_ST (NFC_BASE + 0x28)
|
|
|
|
-++#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
|
|
|
|
-++ defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)
|
|
|
|
-++#define NFC_CONF1 (NFC_BASE + 0x2c)
|
|
|
|
-++#define NFC_ECC_P1 (NFC_BASE + 0x30)
|
|
|
|
-++#define NFC_ECC_P2 (NFC_BASE + 0x34)
|
|
|
|
-++#define NFC_ECC_P3 (NFC_BASE + 0x38)
|
|
|
|
-++#define NFC_ECC_P4 (NFC_BASE + 0x3c)
|
|
|
|
-++#define NFC_ECC_ERR1 (NFC_BASE + 0x40)
|
|
|
|
-++#define NFC_ECC_ERR2 (NFC_BASE + 0x44)
|
|
|
|
-++#define NFC_ECC_ERR3 (NFC_BASE + 0x48)
|
|
|
|
-++#define NFC_ECC_ERR4 (NFC_BASE + 0x4c)
|
|
|
|
-++#define NFC_ADDR2 (NFC_BASE + 0x50)
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++enum _int_stat {
|
|
|
|
-++ INT_ST_ND_DONE = 1<<0,
|
|
|
|
-++ INT_ST_TX_BUF_RDY = 1<<1,
|
|
|
|
-++ INT_ST_RX_BUF_RDY = 1<<2,
|
|
|
|
-++ INT_ST_ECC_ERR = 1<<3,
|
|
|
|
-++ INT_ST_TX_TRAS_ERR = 1<<4,
|
|
|
|
-++ INT_ST_RX_TRAS_ERR = 1<<5,
|
|
|
|
-++ INT_ST_TX_KICK_ERR = 1<<6,
|
|
|
|
-++ INT_ST_RX_KICK_ERR = 1<<7
|
|
|
|
-++};
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++//#define WORKAROUND_RX_BUF_OV 1
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++/*************************************************************
|
|
|
|
-++ * stolen from nand.h
|
|
|
|
-++ *************************************************************/
|
|
|
|
-++
|
|
|
|
-++/*
|
|
|
|
-++ * Standard NAND flash commands
|
|
|
|
-++ */
|
|
|
|
-++#define NAND_CMD_READ0 0
|
|
|
|
-++#define NAND_CMD_READ1 1
|
|
|
|
-++#define NAND_CMD_RNDOUT 5
|
|
|
|
-++#define NAND_CMD_PAGEPROG 0x10
|
|
|
|
-++#define NAND_CMD_READOOB 0x50
|
|
|
|
-++#define NAND_CMD_ERASE1 0x60
|
|
|
|
-++#define NAND_CMD_STATUS 0x70
|
|
|
|
-++#define NAND_CMD_STATUS_MULTI 0x71
|
|
|
|
-++#define NAND_CMD_SEQIN 0x80
|
|
|
|
-++#define NAND_CMD_RNDIN 0x85
|
|
|
|
-++#define NAND_CMD_READID 0x90
|
|
|
|
-++#define NAND_CMD_ERASE2 0xd0
|
|
|
|
-++#define NAND_CMD_RESET 0xff
|
|
|
|
-++
|
|
|
|
-++/* Extended commands for large page devices */
|
|
|
|
-++#define NAND_CMD_READSTART 0x30
|
|
|
|
-++#define NAND_CMD_RNDOUTSTART 0xE0
|
|
|
|
-++#define NAND_CMD_CACHEDPROG 0x15
|
|
|
|
-++
|
|
|
|
-++/* Extended commands for AG-AND device */
|
|
|
|
-++/*
|
|
|
|
-++ * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
|
|
|
|
-++ * there is no way to distinguish that from NAND_CMD_READ0
|
|
|
|
-++ * until the remaining sequence of commands has been completed
|
|
|
|
-++ * so add a high order bit and mask it off in the command.
|
|
|
|
-++ */
|
|
|
|
-++#define NAND_CMD_DEPLETE1 0x100
|
|
|
|
-++#define NAND_CMD_DEPLETE2 0x38
|
|
|
|
-++#define NAND_CMD_STATUS_MULTI 0x71
|
|
|
|
-++#define NAND_CMD_STATUS_ERROR 0x72
|
|
|
|
-++/* multi-bank error status (banks 0-3) */
|
|
|
|
-++#define NAND_CMD_STATUS_ERROR0 0x73
|
|
|
|
-++#define NAND_CMD_STATUS_ERROR1 0x74
|
|
|
|
-++#define NAND_CMD_STATUS_ERROR2 0x75
|
|
|
|
-++#define NAND_CMD_STATUS_ERROR3 0x76
|
|
|
|
-++#define NAND_CMD_STATUS_RESET 0x7f
|
|
|
|
-++#define NAND_CMD_STATUS_CLEAR 0xff
|
|
|
|
-++
|
|
|
|
-++#define NAND_CMD_NONE -1
|
|
|
|
-++
|
|
|
|
-++/* Status bits */
|
|
|
|
-++#define NAND_STATUS_FAIL 0x01
|
|
|
|
-++#define NAND_STATUS_FAIL_N1 0x02
|
|
|
|
-++#define NAND_STATUS_TRUE_READY 0x20
|
|
|
|
-++#define NAND_STATUS_READY 0x40
|
|
|
|
-++#define NAND_STATUS_WP 0x80
|
|
|
|
-++
|
|
|
|
-++typedef enum {
|
|
|
|
-++ FL_READY,
|
|
|
|
-++ FL_READING,
|
|
|
|
-++ FL_WRITING,
|
|
|
|
-++ FL_ERASING,
|
|
|
|
-++ FL_SYNCING,
|
|
|
|
-++ FL_CACHEDPRG,
|
|
|
|
-++ FL_PM_SUSPENDED,
|
|
|
|
-++} nand_state_t;
|
|
|
|
-++
|
|
|
|
-++/*************************************************************/
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++typedef enum _ra_flags {
|
|
|
|
-++ FLAG_NONE = 0,
|
|
|
|
-++ FLAG_ECC_EN = (1<<0),
|
|
|
|
-++ FLAG_USE_GDMA = (1<<1),
|
|
|
|
-++ FLAG_VERIFY = (1<<2),
|
|
|
|
-++} RA_FLAGS;
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++#define BBTTAG_BITS 2
|
|
|
|
-++#define BBTTAG_BITS_MASK ((1<<BBTTAG_BITS) -1)
|
|
|
|
-++enum BBT_TAG {
|
|
|
|
-++ BBT_TAG_UNKNOWN = 0, //2'b01
|
|
|
|
-++ BBT_TAG_GOOD = 3, //2'b11
|
|
|
|
-++ BBT_TAG_BAD = 2, //2'b10
|
|
|
|
-++ BBT_TAG_RES = 1, //2'b01
|
|
|
|
-++};
|
|
|
|
-++
|
|
|
|
-++struct ra_nand_chip {
|
|
|
|
-++ int numchips;
|
|
|
|
-++ int chip_shift;
|
|
|
|
-++ int page_shift;
|
|
|
|
-++ int erase_shift;
|
|
|
|
-++ int oob_shift;
|
|
|
|
-++ int badblockpos;
|
|
|
|
-++#if !defined (__UBOOT__)
|
|
|
|
-++ struct mutex hwcontrol;
|
|
|
|
-++ struct mutex *controller;
|
|
|
|
-++#endif
|
|
|
|
-++ struct nand_ecclayout *oob;
|
|
|
|
-++ int state;
|
|
|
|
-++ unsigned int buffers_page;
|
|
|
|
-++ char *buffers; //[CFG_PAGESIZE + CFG_PAGE_OOBSIZE];
|
|
|
|
-++ char *readback_buffers;
|
|
|
|
-++ unsigned char *bbt;
|
|
|
|
-++#if defined (WORKAROUND_RX_BUF_OV)
|
|
|
|
-++ unsigned int sandbox_page; // steal a page (block) for read ECC verification
|
|
|
|
-++#endif
|
|
|
|
-++
|
|
|
|
-++};
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++//fixme, gdma api
|
|
|
|
-++int nand_dma_sync(void);
|
|
|
|
-++void release_dma_buf(void);
|
|
|
|
-++int set_gdma_ch(unsigned long dst,
|
|
|
|
-++ unsigned long src, unsigned int len, int burst_size,
|
|
|
|
-++ int soft_mode, int src_req_type, int dst_req_type,
|
|
|
|
-++ int src_burst_mode, int dst_burst_mode);
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++
|
|
|
|
-++#endif
|
|
|