Re: [OpenWrt-Devel] [PATCH] ar71xx: add support for the UniFi AP Outdoor Plus
Hello, I succeed to recover a disable command (I followed tips from the Stefan's post). A simple user space configuration utility is in the attachment. Compile it then run the following before a setup of an interface ./hsr 98 What'll be available : scan shows channels 1 and 11; clients on channels 1 and 11 can connect and transmit data; n mode works. I think that they tune an external receiver via some sort of SPI bus (GPIO pins are 5,6,7,8). Write procedure is quite simple, but I can't still get how enable works (for sure it sends a disable); it is quite possible that we need to read from a device before sending a command. Kirill. P.S. Sorry for duplicate from the different address. /* Copyright (c) 2015, Kirill Berezin All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ #include #include #include #include #include #include #include #include #include // High Selectitity Receiver?? Huh ... // device seems to be a SPI bus typedef struct { int csn; // Chip Select, active low int clk;// clock int dout; // data out int din;// data in } hsr_dev_t; void del_dev(hsr_dev_t* dev) { if ( NULL != dev) { if ( -1 != dev->csn) { close(dev->csn); } if ( -1 != dev->clk) { close(dev->clk); } if ( -1 != dev->dout) { close(dev->dout); } if ( -1 != dev->din) { close(dev->din); } dev->csn = -1; dev->clk = -1; dev->dout = -1; dev->din = -1; } } int create_pin(int edesc, int num, char* dir) { char cline[1024]; int ret, ret1, err; int pin_flags; sprintf(cline, "%d", num); write(edesc, cline, strlen(cline)); sprintf(cline, "/sys/class/gpio/gpio%d/direction", num); ret = open(cline, O_WRONLY); if ( -1 == ret) { printf("Can't create pin #%d : %s\n", num, strerror(errno)); return -1; } ret1 = write(ret, dir, strlen(dir)); err = errno; close(ret); if ( -1 == ret1) { printf("Can't configure pin #%d : %s\n", num, strerror(err)); return -1; } pin_flags = !strcmp(dir, "out") ? O_WRONLY : O_RDONLY; sprintf(cline, "/sys/class/gpio/gpio%d/value", num); if ( -1 == (ret = open(cline, pin_flags))) { return -1; } return ret; } int create_dev(hsr_dev_t*dev) { int ret = 0; int gpio_export; gpio_export = open("/sys/class/gpio/export", O_WRONLY); if ( -1 == gpio_export) { printf("Can't open export : %s \n", strerror(errno)); return -1; } if ( -1 == (ret = create_pin(gpio_export, 8, "out"))) { goto over; } dev->csn = ret; if ( -1 == (ret = create_pin(gpio_export, 6, "out"))) { goto over; } dev->clk = ret; if ( -1 == (ret = create_pin(gpio_export, 7, "out"))) { goto over; } dev->dout = ret; if ( -1 == (ret = create_pin(gpio_export, 5, "in"))) { goto over; } dev->din = ret; over: close(gpio_export); return ret; } int dev_write_value(int desc, uint8_t val) { char buf[5]; sprintf(buf, "%d", val%10); return write(desc, buf, 1); } int dev_read_value(int desc) { char buf[32]; long rval; if ( -1 == read(desc, buf, 32)) { printf("can't read a value: %s \n", strerror(errno)); return 1; } rval = strtol(buf, NULL, 10); return (rval >= 1) || (rval < 0) ? 1 : 0; } void hsr_init(hsr_dev_t* dev) { dev_write_value(dev->
Re: [OpenWrt-Devel] [PATCH] ar71xx: add support for the UniFi AP Outdoor Plus
Hi, Updated version is in the attachment. I tried it on a real device, but I can't say that the problem was solved, but something is definitely happens. Unfortunately I couldn't find where a bunch of zeros were generated, so I skipped this part ))) (I tried a version with zeros, but no luck). I also found in the code new commands 115 (lock), 120, 109, and 102. It seems that commands 120 and 109 do not require arguments. And I think that arguments for commands 98 and 102 are sequences of ascii symbols, so the dump you sent can be interpreted as 2 00 00 00 00 00 00 00 00 1 00 01 01 00 00 00 01 00 (the 98 disable command) b(andwidth) 1 00 00 01 01 00 00 01 00 50 1 00 00 01 01 00 00 00 00 48 -> 20 10 00 00 00 00 00 00 00 00 1 00 01 01 01 01 00 00 00 120 x 10 00 00 00 00 00 00 00 00 1 00 01 01 00 01 01 00 01 109 m 10 00 00 00 00 00 00 00 00 1 00 01 01 00 00 01 01 00 102 f(requency) 1 00 00 01 01 00 00 00 00 48 0 1 00 00 01 01 00 00 01 00 50 2 1 00 00 01 01 00 01 00 00 52 4 1 00 00 01 01 00 00 00 01 49 1 1 00 00 01 01 00 01 01 01 55 7 7 00 00 00 00 00 00 00 00 1 00 00 00 00 00 00 00 00 However 2417 is a center for channel 2, but how knows ... Kirill. On 05/21/2015 01:09 AM, Stefan Rompf wrote: Hi, -Trapping ar5416GpioSet with some hand crafted assembly code that traces calls and logs them somewhere this works. I've trapped ar5416GpioSet, putting my code into space occupied by the unused function ar5416GpioCfgInput. ar5416GpioGet is work to do. I can send the code, but it will require adoption to your environment. Tuning to channel 1 revealed the following commands sent via the SPI protocol you discovered (first column is number of repetitions). 2 00 00 00 00 00 00 00 00 1 00 01 01 00 00 00 01 00 (the 98 disable command) 1 00 00 01 01 00 00 01 00 1 00 00 01 01 00 00 00 00 10 00 00 00 00 00 00 00 00 1 00 01 01 01 01 00 00 00 10 00 00 00 00 00 00 00 00 1 00 01 01 00 01 01 00 01 10 00 00 00 00 00 00 00 00 1 00 01 01 00 00 01 01 00 1 00 00 01 01 00 00 00 00 1 00 00 01 01 00 00 01 00 1 00 00 01 01 00 01 00 00 1 00 00 01 01 00 00 00 01 1 00 00 01 01 00 01 01 01 7 00 00 00 00 00 00 00 00 1 00 00 00 00 00 00 00 00 I'll test repeated tuning, other channels and GpioGet next weekend, it's quite in the late evening here by now ;-) Stefan ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel #include #include #include #include #include #include #include #include #include // High Selectivity Receiver?? Huh ... // device seems to be a SPI bus typedef struct { int csn; // Chip Select, active low int clk;// clock int dout; // data out int din;// data in } hsr_dev_t; void del_dev(hsr_dev_t* dev) { if ( NULL != dev) { if ( -1 != dev->csn) { close(dev->csn); } if ( -1 != dev->clk) { close(dev->clk); } if ( -1 != dev->dout) { close(dev->dout); } if ( -1 != dev->din) { close(dev->din); } dev->csn = -1; dev->clk = -1; dev->dout = -1; dev->din = -1; } } int create_pin(int edesc, int num, char* dir) { char cline[1024]; int ret, ret1, err; int pin_flags; sprintf(cline, "%d", num); write(edesc, cline, strlen(cline)); sprintf(cline, "/sys/class/gpio/gpio%d/direction", num); ret = open(cline, O_WRONLY); if ( -1 == ret) { printf("Can't create pin #%d : %s\n", num, strerror(errno)); return -1; } ret1 = write(ret, dir, strlen(dir)); err = errno; close(ret); if ( -1 == ret1) { printf("Can't configure pin #%d : %s\n", num, strerror(err)); return -1; } pin_flags = !strcmp(dir, "out") ? O_WRONLY : O_RDONLY; sprintf(cline, "/sys/class/gpio/gpio%d/value", num); if ( -1 == (ret = open(cline, pin_flags))) { return -1; } return ret; } int create_dev(hsr_dev_t*dev) { int ret = 0; int gpio_export; gpio_export = open("/sys/class/gpio/export", O_WRONLY); if ( -1 == gpio_export) { printf("Can't open export : %s \n", strerror(errno)); return -1; } if ( -1 == (ret = create_pin(gpio_export, 8, "out"))) { goto over; } dev->csn = ret; if ( -1 == (ret = create_pin(gpio_export, 6, "out"))) { goto over; } dev->clk = ret; if ( -1 == (ret = create_pin(gpio_export, 7, "out"))) { goto over; } dev->dout = ret; if ( -1 == (ret = create_pin(gpio_export, 5, "in"))) { goto over; } dev->din = ret; over: close(gpio_export); return ret; } int dev_write_value(int desc, uint8_t val) { char buf[5]; sprintf(buf, "%d", val%10); int ret = write(desc, buf, strlen(buf)); //printf("ret %d %s \n", ret, ret < 0 ? strerror(errno) : " "); return ret; } int dev_rea
Re: [OpenWrt-Devel] [PATCH] ar71xx: add support for the UniFi AP Outdoor Plus
> I haven't been able to get the reset button on boot to work for UniFi. > I use UART to pull up the boot-loader. Then use "urescue" to tftp the > UniFi image back on. reset button works, but it's not easy to get whether it is pressed or not. If a reset button pressed then after a while AP light a pale blue for a couple of seconds then blinks with two colors. To recover you need an image of jffs2 partition. I made a copy from working system and used this copy for recovery. I wrote it in openwrt with mtd to firmware partition. The image bundled with a controller contains a bootloader and a kernel, but it lacks a root filesystem. Moreover the stock bootloader can't write this image, so the procedure published in ubiquity forums doesn't work for ap+. Kirill. ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
Re: [OpenWrt-Devel] [PATCH] ar71xx: add support for the UniFi AP Outdoor Plus
Hi, Well, this was my bad )) I accidentally chose cpu's gpio and realised that this is a mistake yesterday night. So I made a patch for atheros driver and it works. A signal level on different frequencies is more or less equal and seems adequate (about -30 dbm if a client within a meter from ap). The patch for bb 14.07 is in the attachment. It should be placed in package/kernel/mac80211/patches . The code generates a lot of messages, so it'll be easy to track what happens. Kirill On 05/26/2015 11:25 PM, Stefan Rompf wrote: Until I found that I was accessing GPIO lines of the CPU (cat /sys/devices/virtual/gpio/gpiochip0/label => ath79), not of the 928x wifi chip. It seems that ath9k does not even export its pins to the GPIO subsystem. Stefan diff -urN old/drivers/net/wireless/ath/ath9k/hsr.c new/drivers/net/wireless/ath/ath9k/hsr.c --- old/drivers/net/wireless/ath/ath9k/hsr.c 1970-01-01 03:00:00.0 +0300 +++ new/drivers/net/wireless/ath/ath9k/hsr.c 2015-05-27 12:47:43.0 +0300 @@ -0,0 +1,236 @@ +/* + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Kirill Berezin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hw.h" +#include "hw-ops.h" +#include "ar9003_mac.h" +#include "ar9003_mci.h" +#include "ar9003_phy.h" +#include "ath9k.h" + +#include "hsr.h" + +void hsr_init(struct ath_hw* ah) { + + if ( NULL == ah) { + return; + } + + ath9k_hw_cfg_gpio_input(ah, HSR_GPIO_DIN); + ath9k_hw_cfg_output(ah, HSR_GPIO_CSN, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_cfg_output(ah, HSR_GPIO_CLK, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_cfg_output(ah, HSR_GPIO_DOUT, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0); + + udelay(HSR_DELAY_TRAILING); + + printk(KERN_NOTICE "hsr_init: done"); + +} +EXPORT_SYMBOL(hsr_init); + +static u32 hsr_write_byte(struct ath_hw* ah, int delay, u32 value){ + int i; + u32 rval = 0; + + udelay(delay); + + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); + udelay(HSR_DELAY_HALF_TICK); + + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0); + udelay(HSR_DELAY_HALF_TICK); + + for( i = 0; i < 8; ++i) { + rval = rval << 1; + + // pattern is left to right, that is 7-th bit runs first + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1); + udelay(HSR_DELAY_HALF_TICK); + + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1); + udelay(HSR_DELAY_HALF_TICK); + + rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN); + + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); + udelay(HSR_DELAY_HALF_TICK); + } + + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); + udelay(HSR_DELAY_HALF_TICK); + +printk(KERN_NOTICE "hsr_write_byte: write byte %d return value is %x %d %c \n", value, rval, rval, rval > 32 ? rval : '-'); + + return rval & 0xff; +} + +static int hsr_write_a_chain(struct ath_hw* ah, char* chain, int items) { + int i = 0, j; + int status = 0; + int loops = 0; + // a preabmle + hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); + + status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); + + if ( status) { + int loop = 2; + ++ loops; + if ( loops > 42) { +printk(KERN_NOTICE "hsr_write_a_chain: too many loops in preamble. giving up.\n"); + return 0; + } + do { + status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); + loop = (loop + 1) & 0x; + if ( loop < 2) { +continue; + } + } while(status); + } + +for ( i =0; (i < items) && ( 0 != chain[i]); ++i) { + hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]); + } + hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); + udelay(HSR_DELAY_FINAL); + + memset(chai
Re: [OpenWrt-Devel] ar71xx: How to integrate UniFi AP Outdoor Plus HSR?
Hi, Stefan On 05/27/2015 11:48 PM, Stefan Rompf wrote: Integration into the kernel driver like your latest patch does. Caveat: The build process seems to assume that all routers in the ar71xx/generic target share the same set of kernel modules. So patching and compiling yourself is no problem, but a working image on downloads.openwrt.org is not feasible as every router would get the HSR driver. Correct me if I am wrong. This is not a problem because it is possible to use full platform name, which includes a profile name, as a dependency. The ubiquity driver checks some flags before enabling hsr, but I can't still track down where they store them. May be somewhere in eeprom. Or making ath9k expose the gpio and driving from user space. A generic patch for ath9k to register its gpio pins via the standard gpio subsystem. This should go upstream to the kernel and may prove usable for other access points to. An Unifi specific user space daemon listens to scan and channel change events via netlink (will check next weekend if channel change is broadcasted reliably) and tune the filter via sysfs interface accordingly like hsr.c tried. I like this idea because in this case it'll be much easier to correct problems or add changes. However for more general use a patch to the driver is much better. PS: I've started working on the wiki page http://wiki.openwrt.org/toh/ubiquiti/unifi_outdoorplus that I hope to move to "supported" soon ;-) I have a couple photos of pcb (one with annotated serial port), can send them if you need. Kirill. ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
Re: [OpenWrt-Devel] [PATCH RFC] Add support for Ubiquiti Unifi Outdoor Plus
Hi Stefan, I have a couple of suggestions. First of all I think it will be better to initialize static variables in hsr_tune with zeroes : > ++static void hsr_tune(struct ath_hw* ah, int bw, int fq) { > ++ static int initialized = 0; > ++ static int last_bw = 0, last_fq = 0; And I have an updated versions of write functions. I added to hsr_write_byte debug messages that can be activated by atheros CONFIG flag (of course atheros debugging must be compiled in). Also I simplified loops in hsr_write_a_chain because it seems that they are needed to get data from a some sort of output buffer which includes less than 6 bytes. static u32 hsr_write_byte(struct ath_hw* ah, int delay, u32 value){ int i; u32 rval = 0; struct ath_common *common = ath9k_hw_common(ah); udelay(delay); ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); udelay(HSR_DELAY_HALF_TICK); ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0); udelay(HSR_DELAY_HALF_TICK); for( i = 0; i < 8; ++i) { rval = rval << 1; // pattern is left to right, that is 7-th bit runs first ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1); udelay(HSR_DELAY_HALF_TICK); ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1); udelay(HSR_DELAY_HALF_TICK); rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN); ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); udelay(HSR_DELAY_HALF_TICK); } ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); udelay(HSR_DELAY_HALF_TICK); ath_dbg(common, CONFIG, "hsr_write_byte: write byte %d return value is %d %c \n", value, rval, rval > 32 ? rval : '-'); return rval & 0xff; } static int hsr_write_a_chain(struct ath_hw* ah, char* chain, int items) { int i = 0; int status = 0; hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); // clear HSR's reply buffer if ( status) { int loop = 0; for ( loop = 0; (loop < 42) && status; ++loop) { status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); } if ( loop >= 42) { printk(KERN_WARNING "hsr_write_a_chain: can't clear an output buffer after a 42 cycles.\n"); return 0; } } // data for ( i =0; (i < items) && ( 0 != chain[i]); ++i) { hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]); } hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); udelay(HSR_DELAY_FINAL); // reply memset(chain, 0, items); hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); udelay(HSR_DELAY_TRAILING); for ( i = 0; i < (items - 1); ++i) { u32 ret; if ( 0 != (ret = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0))) { chain[i] = (char)ret; } else { break; } udelay(HSR_DELAY_TRAILING); } return (1 < i) ? simple_strtol(chain + 1, NULL, 10) : 0; } > I also tried to change target/linux/ar71xx/generic/profiles/ubnt.mk and > target/linux/ar71xx/image/Makefile to include this module into the > UBNTUNIFIOUTDOORPLUS image, but this fails. Any idea why? May be this happens when building a bunch of different profiles at once? Kirill. On 06/06/2015 04:28 PM, Stefan Rompf wrote: Hi, please review my patch to add support for the Ubiquiti Unifi Outdoor Plus access point based on the work of Kirill Berezin and me. The access point has a configurable RF filter in the receive path that must be tuned according to the selected Wifi channel. A patch to compat_wireless adds support to register a callback to the ath9k driver that is called whenever the channel changes. It also adds hsr.c, the channel change helper that tunes the filter connected to the AR9287 GPIO pins. I'm running this part successfully on top of the Chaos Calmer RC1 image. A new configuration option to create the kmod-ath-hsr. It contains the driver .ko and must be installed on the access point. This is compile tested on trunk. I also tried to change target/linux/ar71xx/generic/profiles/ubnt.mk and target/linux/ar71xx/image/Makefile to include this module into the UBNTUNIFIOUTDOORPLUS image, but this fails. Any idea why? Comments? Stefan Index: package/kernel/mac80211/Makefile === --- package/kernel/mac80211/Makefile(Revision 45907) +++ package/kernel/mac80211/Makefile(Arbeitskopie) @@ -27,7 +27,7 @@ rt2x00-lib rt2x00-pci rt2x00-usb rt2800-lib rt2400-pci rt2500-pci \ rt2500-usb rt61-pci rt73-usb rt2800-mmio rt2800-pci rt2800-usb rt2800-soc \ rtl8180 rtl8187 zd1211rw mac
[OpenWrt-Devel] [RCF] A patch for mt7621 nand controller.
Hello. It seems that a code for a nand controller was added but not tested. This patch add a lost constant required for successful compilation and a bit of code that allocates and frees buffers needed by internal structures and a description for two more nand chips. By the way I found, that a nand controller in some way interferes with spi flash and sd. If I initialize a nand before spi flash or sd then nand controller becomes busy or returns ecc errors on every read. If I initialize, say load as module, it after spi flash or sd then everything works. I can't say what happens with sd or spi flash because my board have neither of it. May be I have an incorrect dts file. Kirill --- a/drivers/mtd/nand/mtk_nand.c 2015-10-22 12:42:37.783545248 +0400 +++ b/drivers/mtd/nand/mtk_nand.c 2015-10-22 12:32:47.0 +0400 @@ -110,6 +110,10 @@ int manu_id; int dev_id; +/* this constant was taken from linux/nand/nand.h v 3.14 + * in later versions it seems it was removed in order to save a bit of space + */ +#define NAND_MAX_OOBSIZE 774 static u8 local_oob_buf[NAND_MAX_OOBSIZE]; static u8 nand_badblock_offset = 0; @@ -2175,6 +2184,25 @@ nand_chip->pagemask = (nand_chip->chipsize >> nand_chip->page_shift) - 1; nand_chip->phys_erase_shift = ffs(mtd->erasesize) - 1; nand_chip->chip_shift = ffs(nand_chip->chipsize) - 1;//0x1C;//ffs(nand_chip->chipsize) - 1; + + /* this was taken from nand_base.c ##3876 nand_scan_tail */ + if (!(nand_chip->options & NAND_OWN_BUFFERS)) { + struct nand_buffers *nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize + mtd->oobsize * 3, GFP_KERNEL); + if (!nbuf) { + return -ENOMEM; + } + nbuf->ecccalc = (uint8_t *)(nbuf + 1); + nbuf->ecccode = nbuf->ecccalc + mtd->oobsize; + nbuf->databuf = nbuf->ecccode + mtd->oobsize; + + nand_chip->buffers = nbuf; + } else { + if (!nand_chip->buffers) { + printk(KERN_NOTICE "mtk_nand_probe: buffer space for nand_chip was not allocated.\n"); + return -ENOMEM; + } + } + nand_chip->oob_poi = nand_chip->buffers->databuf + mtd->writesize; nand_chip->badblockpos = 0; @@ -2251,6 +2279,9 @@ MSG(INIT, "[NFI] mtk_nand_probe fail, err = %d!\n", err); nand_release(mtd); platform_set_drvdata(pdev, NULL); + if ( NULL != nand_chip->buffers) { + kfree(nand_chip->buffers); + } kfree(host); nand_disable_clock(); return err; @@ -2261,8 +2292,12 @@ { struct mtk_nand_host *host = platform_get_drvdata(pdev); struct mtd_info *mtd = &host->mtd; + struct nand_chip *nand_chip = &host->nand_chip; nand_release(mtd); + if ( NULL != nand_chip->buffers) { + kfree(nand_chip->buffers); + } kfree(host); nand_disable_clock(); --- a/drivers/mtd/nand/nand_device_list.h 2015-10-22 12:42:37.784545248 +0400 +++ b/drivers/mtd/nand/nand_device_list.h 2015-10-22 09:40:33.0 +0400 @@ -43,6 +43,8 @@ {0xADBC, 0x905554, 5, 16, 512, 128, 2048, 64, 0x10801011, "H9DA4GH4JJAMC", 0}, {0x01F1, 0x801D01, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "S34ML01G100TF", 0}, {0x92F1, 0x8095FF, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "F59L1G81A", 0}, + {0xC8DA, 0x909544, 5, 8, 256, 128, 2048, 64, 0x30C77fff, "F59L2G81A", 0}, + {0xC8DC, 0x909554, 5, 8, 512, 128, 2048, 64, 0x30C77fff, "F59L4G81A", 0}, {0xECD3, 0x519558, 5, 8, 1024, 128, 2048, 64, 0x44333, "K9K8G8000", 0}, {0xC2F1, 0x801DC2, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "MX30LF1G08AA", 0}, {0x98D3, 0x902676, 5, 8, 1024, 256, 4096, 224, 0x00C25332, "TC58NVG3S0F", 0}, ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
[OpenWrt-Devel] [RFC] A patch for mt7621 nand controler. Revision 2.
Hello, It turned out that mtk_nand driver uses some sophisticated accounting and a general nand code must be patched. This patch adds required read and erase calls to a general nand code. I used a code for re6500 released by Linksys as a reference. All required operations (erase, write and read) are usable. However I found that jffs2 filesystem can be created only on top of a ubi volume. I tried to create jffs2 directly on mtd device but pages with clean markers are became uncorrectable. This patch also includes changes that I sent earlier. Best regards, Kirill. Signed-off-by: Kirill Berezin (fyi...@gmail.com) diff -urNb a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c --- a/drivers/mtd/nand/mtk_nand.c 2015-11-06 16:44:31.0 +0400 +++ b/drivers/mtd/nand/mtk_nand.c 2015-11-12 10:06:20.080430855 +0400 @@ -110,6 +110,10 @@ int manu_id; int dev_id; +/* this constant was taken from linux/nand/nand.h v 3.14 + * in later versions it seems it was removed in order to save a bit of space + */ +#define NAND_MAX_OOBSIZE 774 static u8 local_oob_buf[NAND_MAX_OOBSIZE]; static u8 nand_badblock_offset = 0; @@ -348,7 +352,7 @@ if (0xF == u4ErrNum) { mtd->ecc_stats.failed++; bRet = false; - //printk(KERN_ERR"UnCorrectable at PageAddr=%d\n", u4PageAddr); + printk(KERN_ERR"mtk_nand: UnCorrectable at PageAddr=%d\n", u4PageAddr); } else { for (i = 0; i < ((u4ErrNum + 1) >> 1); ++i) { au4ErrBitLoc[i] = DRV_Reg32(ECC_DECEL0_REG32 + i); @@ -1422,7 +1426,7 @@ { struct nand_chip *chip = (struct nand_chip *)mtd->priv; - chip->erase_cmd(mtd, page); + chip->erase(mtd, page); return chip->waitfunc(mtd, chip); } @@ -2094,8 +2098,8 @@ nand_chip->write_page = mtk_nand_write_page; nand_chip->ecc.write_oob = mtk_nand_write_oob; nand_chip->block_markbad = mtk_nand_block_markbad; // need to add nand_get_device()/nand_release_device(). - // nand_chip->erase = mtk_nand_erase; - //nand_chip->read_page = mtk_nand_read_page; + nand_chip->erase_mtk = mtk_nand_erase; + nand_chip->read_page = mtk_nand_read_page; nand_chip->ecc.read_oob = mtk_nand_read_oob; nand_chip->block_bad = mtk_nand_block_bad; @@ -2175,6 +2179,21 @@ nand_chip->pagemask = (nand_chip->chipsize >> nand_chip->page_shift) - 1; nand_chip->phys_erase_shift = ffs(mtd->erasesize) - 1; nand_chip->chip_shift = ffs(nand_chip->chipsize) - 1;//0x1C;//ffs(nand_chip->chipsize) - 1; + + /* allocate buffers or call select_chip here or a bit earlier*/ + { + struct nand_buffers *nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize + mtd->oobsize * 3, GFP_KERNEL); + if (!nbuf) { + return -ENOMEM; + } + nbuf->ecccalc = (uint8_t *)(nbuf + 1); + nbuf->ecccode = nbuf->ecccalc + mtd->oobsize; + nbuf->databuf = nbuf->ecccode + mtd->oobsize; + + nand_chip->buffers = nbuf; + nand_chip->options |= NAND_OWN_BUFFERS; + } + nand_chip->oob_poi = nand_chip->buffers->databuf + mtd->writesize; nand_chip->badblockpos = 0; @@ -2251,6 +2270,9 @@ MSG(INIT, "[NFI] mtk_nand_probe fail, err = %d!\n", err); nand_release(mtd); platform_set_drvdata(pdev, NULL); + if ( NULL != nand_chip->buffers) { + kfree(nand_chip->buffers); + } kfree(host); nand_disable_clock(); return err; @@ -2261,8 +2283,12 @@ { struct mtk_nand_host *host = platform_get_drvdata(pdev); struct mtd_info *mtd = &host->mtd; + struct nand_chip *nand_chip = &host->nand_chip; nand_release(mtd); + if ( NULL != nand_chip->buffers) { + kfree(nand_chip->buffers); + } kfree(host); nand_disable_clock(); diff -urNb a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c --- a/drivers/mtd/nand/nand_base.c 2015-11-06 16:44:31.0 +0400 +++ b/drivers/mtd/nand/nand_base.c 2015-11-09 10:24:52.931720862 +0400 @@ -1575,6 +1575,9 @@ __func__, buf); read_retry: +#ifdef CONFIG_MTK_MTD_NAND + ret = chip->read_page(mtd, chip, bufpoi, page); +#else chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); /* @@ -1593,6 +1596,7 @@ else ret = chip->ecc.read_page(mtd, chip, bufpoi, oob_required, page); +#endif /* CONFIG_MTK_MTD_NAND */ if (ret < 0) { if (use_bufpoi) /* Invalidate page cache */ @@ -2770,8 +2774,11 @@ if (page <= chip->pagebuf && chip->pagebuf < (page + pages_per_block)) chip->pagebuf = -1; - +#ifdef CONFIG_MTK_MTD_NAND + status = chip->erase_mtk(mtd, page & chip->pagemask); +#else status = chip->erase(mtd, page & chip->pagemask); +#endif /* CONFIG_MTK_MTD_NAND */ /* * See if operation failed and additional status checks are diff -urNb a/drivers/mtd/nand/nand_device_list.h b/drivers/mtd/nand/nand_device_list.h --- a/drivers/mtd/nand/nand_device_list.h 2015-11-06 16:44:31.0 +0400 +++ b/drivers/mtd
[OpenWrt-Devel] RFC. AR231x/AR5312 build failure fix.
Hie! I found that it is not possible to build openwrt current for ar231x platform. It fails building gpio related modules with messages ... MODPOST 343 modules ERROR: "ar231x_gpiodev" [drivers/w1/masters/w1-gpio.ko] undefined! ERROR: "ar231x_gpiodev" [drivers/spi/spi_gpio_old.ko] undefined! ERROR: "ar231x_gpiodev" [drivers/spi/spi_gpio.ko] undefined! ERROR: "ar231x_gpiodev" [drivers/input/misc/gpio_buttons.ko] undefined! ERROR: "ar231x_gpiodev" [drivers/i2c/busses/i2c-gpio.ko] undefined! ... Eventually I found cmd for all of this modules includes arch/mips/include/ar231x/gpio.h with an extern variable called ar231x_gpiodev. After short googling I found such variables must have EXPORT_SYMBOL after definition. I found definition in arch/mips/ar231x/devices.c. I hope the following patch will be helpful. --- ./build_dir/linux-atheros/linux-2.6.28.10/arch/mips/ar231x/devices.c_old 2009-07-06 13:28:01.099918653 +0400 +++ ./build_dir/linux-atheros/linux-2.6.28.10/arch/mips/ar231x/devices.c 2009-07-06 13:28:06.734699709 +0400 @@ -13,6 +13,7 @@ struct ar231x_board_config ar231x_board; int ar231x_devtype = DEV_TYPE_UNKNOWN; const struct ar231x_gpiodev *ar231x_gpiodev; +EXPORT_SYMBOL(ar231x_gpiodev); static struct resource ar231x_eth0_res[] = { { Kirill. -- Кирилл Березин Старший инженер-программист Группа развития ISP систем, Совинтел Группа Компаний ВымпелКом ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel