static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *chip = mtd->priv; struct s3c2410_nand *nand = s3c2410_get_base_nand(); debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl); if (ctrl & NAND_CTRL_CHANGE) { ulong IO_ADDR_W = (ulong)nand; if (!(ctrl & NAND_CLE)) IO_ADDR_W |= S3C2410_ADDR_NCLE; if (!(ctrl & NAND_ALE)) IO_ADDR_W |= S3C2410_ADDR_NALE; chip->IO_ADDR_W = (void *)IO_ADDR_W; if (ctrl & NAND_NCE) writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE, &nand->nfconf); else writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE, &nand->nfconf); } if (cmd != NAND_CMD_NONE) writeb(cmd, chip->IO_ADDR_W); }
static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { struct s3c2410_nand *nand = s3c2410_get_base_nand(); ecc_code[0] = readb(&nand->nfecc); ecc_code[1] = readb(&nand->nfecc + 1); ecc_code[2] = readb(&nand->nfecc + 2); debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n", mtd , ecc_code[0], ecc_code[1], ecc_code[2]); return 0; }
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { int i, dev, ret = 0; ulong addr, off; size_t size; char *cmd, *s; nand_info_t *nand; #ifdef CONFIG_SYS_NAND_QUIET int quiet = CONFIG_SYS_NAND_QUIET; #else int quiet = 0; #endif const char *quiet_str = getenv("quiet"); /* at least two arguments please */ if (argc < 2) goto usage; if (quiet_str) quiet = simple_strtoul(quiet_str, NULL, 0) != 0; cmd = argv[1]; if (strcmp(cmd, "info") == 0) { putc('\n'); for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { if (nand_info[i].name) nand_print_info(i); } return 0; } if (strcmp(cmd, "device") == 0) { if (argc < 3) { putc('\n'); if ((nand_curr_device < 0) || (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE)) puts("no devices available\n"); else nand_print_info(nand_curr_device); return 0; } dev = (int)simple_strtoul(argv[2], NULL, 10); if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev].name) { puts("No such device\n"); return 1; } printf("Device %d: %s", dev, nand_info[dev].name); puts("... is now current device\n"); nand_curr_device = dev; #ifdef CONFIG_SYS_NAND_SELECT_DEVICE /* * Select the chip in the board/cpu specific driver */ board_nand_select_device(nand_info[dev].priv, dev); #endif return 0; } if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 && strncmp(cmd, "dump", 4) != 0 && strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 && strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && strcmp(cmd, "biterr") != 0 && strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 ) goto usage; /* the following commands operate on the current device */ if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[nand_curr_device].name) { puts("\nno devices available\n"); return 1; } nand = &nand_info[nand_curr_device]; if (strcmp(cmd, "bad") == 0) { printf("\nDevice %d bad blocks:\n", nand_curr_device); for (off = 0; off < nand->size; off += nand->erasesize) if (nand_block_isbad(nand, off)) printf(" %08lx\n", off); return 0; } /* * Syntax is: * 0 1 2 3 4 * nand erase [clean] [off size] */ if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) { nand_erase_options_t opts; /* "clean" at index 2 means request to write cleanmarker */ int clean = argc > 2 && !strcmp("clean", argv[2]); int o = clean ? 3 : 2; int scrub = !strcmp(cmd, "scrub"); printf("\nNAND %s: ", scrub ? "scrub" : "erase"); /* skip first two or three arguments, look for offset and size */ if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0) return 1; memset(&opts, 0, sizeof(opts)); opts.offset = off; opts.length = size; opts.jffs2 = clean; opts.quiet = quiet; if (scrub) { puts("Warning: " "scrub option will erase all factory set " "bad blocks!\n" " " "There is no reliable way to recover them.\n" " " "Use this command only for testing purposes " "if you\n" " " "are sure of what you are doing!\n" "\nReally scrub this NAND flash? <y/N>\n"); if (getc() == 'y' && getc() == '\r') { opts.scrub = 1; } else { puts("scrub aborted\n"); return -1; } } ret = nand_erase_opts(nand, &opts); printf("%s\n", ret ? "ERROR" : "OK"); return ret == 0 ? 0 : 1; } if (strncmp(cmd, "dump", 4) == 0) { if (argc < 3) goto usage; s = strchr(cmd, '.'); off = (int)simple_strtoul(argv[2], NULL, 16); if (s != NULL && strcmp(s, ".oob") == 0) ret = nand_dump(nand, off, 1); else ret = nand_dump(nand, off, 0); return ret == 0 ? 1 : 0; } if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { int read; if (argc < 4) goto usage; addr = (ulong)simple_strtoul(argv[2], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: ", read ? "read" : "write"); if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) return 1; s = strchr(cmd, '.'); if (!s || !strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &size, (u_char *)addr); else ret = nand_write_skip_bad(nand, off, &size, (u_char *)addr); } //添加yaffs2相关操作,注意该处又关联到nand_write_skip_bad函数 #if defined(CONFIG_MTD_NAND_YAFFS2) else if (s != NULL && (!strcmp(s, ".yaffs2"))) { debugX(1, "write yaffs2\n"); nand->rw_oob = 1; nand->skipfirstblk = 1; ret = nand_write_skip_bad(nand,off,&size,(u_char *)addr); nand->skipfirstblk = 0; nand->rw_oob = 0; } #endif else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { .oobbuf = (u8 *)addr, .ooblen = size, .mode = MTD_OOB_RAW }; if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); } else {
uint8 ValveContron_Delu(MeterFileType *p_mf, uint8 functype, uint8 *p_DataIn, uint8 *p_databuf, uint8 *p_datalenback) { uint8 Err = 0; uint8 lu8data[100] = {0}; uint8 lu8databuf[20] = {0xee}; uint8 lu8datalenback = 0; CJ188_Format lMeterData; DELU_Protocol ProtocoalInfo; ProtocoalInfo.PreSmybolNum = 0x04; ProtocoalInfo.MeterType = 0x20; memcpy(ProtocoalInfo.MeterAddr, p_mf->ValveAddr, 7); ProtocoalInfo.ControlCode = 0x04; ProtocoalInfo.SER = 0; switch(functype) { case ReadVALVE_All: //对德鲁协议来说,包括读室内温度和阀门状态2方面。 { ProtocoalInfo.Length = 0x0B; ProtocoalInfo.DataIdentifier = 0x20A0; memcpy(ProtocoalInfo.DataBuf, p_mf->ControlPanelAddr, 7); ProtocoalInfo.DataBuf[7] = 0x11; Err = METER_DataItem(&ProtocoalInfo); if(Err == NO_ERR) { memcpy(lu8data, ProtocoalInfo.DataBuf, (ProtocoalInfo.Length - 3)); if(lu8data[0] == 0xff) { memset(lu8databuf, 0xee, 3); } else { memcpy(lu8databuf, lu8data, 3); } lu8datalenback += 3; } else { memset(lu8databuf, 0xee, 3); //温度3个字节 lu8datalenback += 3; } //读取阀门状态!! ProtocoalInfo.PreSmybolNum = 0x04; //经过上面读室内温度,ProtocoalInfo中有一些量改变了,所以重赋值。 ProtocoalInfo.MeterType = 0x20; memcpy(ProtocoalInfo.MeterAddr, p_mf->ValveAddr, 7); ProtocoalInfo.ControlCode = 0x04; ProtocoalInfo.SER = 0; ProtocoalInfo.Length = 0x04; ProtocoalInfo.DataIdentifier = 0x24A0; ProtocoalInfo.DataBuf[0] = 0x11; Err = METER_DataItem(&ProtocoalInfo); if(Err == NO_ERR) { uint16 ValveState = 0; ValveState = *(uint16 *)ProtocoalInfo.DataBuf; if(ValveState == 0x0800 || ValveState == 0x9900) { ValveState = 0x0099; }/*全关*/ else if(ValveState == 0x0400 || ValveState == 0x8800) { ValveState = 0x0088; } else if(ValveState == 0x0200 || ValveState == 0x7700) { ValveState = 0x0077; } else if(ValveState == 0x0100 || ValveState == 0x6600) { ValveState = 0x0066; } else if(ValveState == 0x0000 || ValveState == 0x5500) { ValveState = 0x0055; }/*全开*/ else { ValveState = 0x0099; } lu8databuf[3] = (uint8)ValveState; //阀门开度字节 lu8databuf[4] = 0;//按照格式补齐。 lu8databuf[5] = 0; lu8datalenback += 3; } else { memset(&lu8databuf[3], 0xee, 3); //温度3个字节 lu8datalenback += 3; } memcpy(p_databuf, lu8databuf, lu8datalenback); *p_datalenback = lu8datalenback; break; } case READROOM_TEMP: { ProtocoalInfo.Length = 0x0B; ProtocoalInfo.DataIdentifier = 0x20A0; memcpy(ProtocoalInfo.DataBuf, p_mf->ControlPanelAddr, 7); ProtocoalInfo.DataBuf[7] = 0x11; Err = METER_DataItem(&ProtocoalInfo); if(Err == NO_ERR) { memcpy(lu8data, ProtocoalInfo.DataBuf, (ProtocoalInfo.Length - 3)); if(lu8data[0] == 0xff) { memset(lu8databuf, 0xee, 3); } else { lu8databuf[0] = lu8data[2]; //因协议格式,调换顺序。 lu8databuf[1] = lu8data[1]; lu8databuf[2] = lu8data[0]; } lu8datalenback += 3; } else { memset(lu8databuf, 0xee, 3); //温度3个字节 lu8datalenback += 3; } memcpy(p_databuf, lu8databuf, lu8datalenback); *p_datalenback = lu8datalenback; break; } case SETHEAT_DISPLAY: { break; } case SETHEAT_VALUE: { ProtocoalInfo.Length = 0x2E; ProtocoalInfo.DataIdentifier = 0x25A0; memcpy(ProtocoalInfo.DataBuf, p_DataIn, sizeof(lMeterData)); Err = METER_DataItem(&ProtocoalInfo); if(Err == NO_ERR) { debug_info(gDebugModule[TASKDOWN_MODULE], "%s %d Send HeatMeter data to valve ok", __FUNCTION__, __LINE__); } else { debugX(LOG_LEVEL_ERROR, "%s %d Send HeatMeter data to valve failed!\r\n", __FUNCTION__, __LINE__); } break; } case SETROOM_TEMP: { ProtocoalInfo.Length = 0x0D; ProtocoalInfo.DataIdentifier = 0x23A0; memcpy(ProtocoalInfo.DataBuf, p_mf->ControlPanelAddr, 7); //memcpy(&ProtocoalInfo.DataBuf[7], p_DataIn, 3); ProtocoalInfo.DataBuf[7] = *(p_DataIn + 2); //按照德鲁阀控协议调整顺序。 ProtocoalInfo.DataBuf[8] = *(p_DataIn + 1); ProtocoalInfo.DataBuf[9] = *(p_DataIn + 0); Err = METER_DataItem(&ProtocoalInfo); if(Err == NO_ERR) { memcpy(lu8data, ProtocoalInfo.DataBuf, (ProtocoalInfo.Length - 3)); lu8datalenback = ProtocoalInfo.Length - 3; } memcpy(p_databuf, lu8data, lu8datalenback); *p_datalenback = lu8datalenback; break; } case SETTEMP_RANGE: { ProtocoalInfo.Length = 0x10; ProtocoalInfo.DataIdentifier = 0x21A0; memcpy(ProtocoalInfo.DataBuf, p_mf->ControlPanelAddr, 7); //memcpy(&ProtocoalInfo.DataBuf[7], p_DataIn, 6); ProtocoalInfo.DataBuf[7] = *(p_DataIn + 2); //按照德鲁阀控协议调整顺序。 ProtocoalInfo.DataBuf[8] = *(p_DataIn + 1); ProtocoalInfo.DataBuf[9] = *(p_DataIn + 0); ProtocoalInfo.DataBuf[10] = *(p_DataIn + 5); //按照德鲁阀控协议调整顺序。 ProtocoalInfo.DataBuf[11] = *(p_DataIn + 4); ProtocoalInfo.DataBuf[12] = *(p_DataIn + 3); Err = METER_DataItem(&ProtocoalInfo); if(Err == NO_ERR) { memcpy(lu8data, ProtocoalInfo.DataBuf, (ProtocoalInfo.Length - 3)); lu8datalenback = ProtocoalInfo.Length - 3; } memcpy(p_databuf, lu8data, lu8datalenback); *p_datalenback = lu8datalenback; break; } case SETVALVE_STATUS: { ProtocoalInfo.Length = 0x04; ProtocoalInfo.DataIdentifier = 0x17A0; ProtocoalInfo.DataBuf[0] = *(p_DataIn + 0); Err = METER_DataItem(&ProtocoalInfo); if(Err == NO_ERR) { memcpy(lu8data, ProtocoalInfo.DataBuf, (ProtocoalInfo.Length - 3)); lu8datalenback = ProtocoalInfo.Length - 3; } memcpy(p_databuf, lu8data, lu8datalenback); *p_datalenback = lu8datalenback; break; } case SETVALVE_CONTROLTYPE: { ProtocoalInfo.Length = 0x0B; ProtocoalInfo.DataIdentifier = 0x22A0; memcpy(ProtocoalInfo.DataBuf, p_mf->ControlPanelAddr, 7); if(*(p_DataIn + 0) == 0x09) { ProtocoalInfo.DataBuf[7] = 0x55; } if(*(p_DataIn + 0) == 0x0B) { ProtocoalInfo.DataBuf[7] = 0x66; } if(*(p_DataIn + 0) == 0x0C) { ProtocoalInfo.DataBuf[7] = 0x77; } if(*(p_DataIn + 0) == 0x0D) { ProtocoalInfo.DataBuf[7] = 0x88; } Err = METER_DataItem(&ProtocoalInfo); if(Err == NO_ERR) { memcpy(lu8data, ProtocoalInfo.DataBuf, (ProtocoalInfo.Length - 3)); lu8datalenback = ProtocoalInfo.Length - 3; } memcpy(p_databuf, lu8data, lu8datalenback); *p_datalenback = lu8datalenback; break; } case READVALVE_STATUS: { //读取阀门状态!! ProtocoalInfo.Length = 0x04; ProtocoalInfo.DataIdentifier = 0x24A0; ProtocoalInfo.DataBuf[0] = 0x11; Err = METER_DataItem(&ProtocoalInfo); if(Err == NO_ERR) { uint16 ValveState = 0; ValveState = *(uint16 *)ProtocoalInfo.DataBuf; if(ValveState == 0x0800 || ValveState == 0x9900) { ValveState = 0x0099; }/*全关*/ else if(ValveState == 0x0400 || ValveState == 0x8800) { ValveState = 0x0088; } else if(ValveState == 0x0200 || ValveState == 0x7700) { ValveState = 0x0077; } else if(ValveState == 0x0100 || ValveState == 0x6600) { ValveState = 0x0066; } else if(ValveState == 0x0000 || ValveState == 0x5500) { ValveState = 0x0055; }/*全开*/ else { ValveState = 0x0099; } lu8databuf[0] = (uint8)ValveState; //阀门开度字节 lu8datalenback += 1; } memcpy(p_databuf, lu8databuf, lu8datalenback); *p_datalenback = lu8datalenback; break; } default: break; } return Err; }
void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) { struct s3c2410_nand *nand = s3c2410_get_base_nand(); debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode); writel(readl(&nand->nfconf) | S3C2410_NFCONF_INITECC, &nand->nfconf); }
static int s3c2410_dev_ready(struct mtd_info *mtd) { struct s3c2410_nand *nand = s3c2410_get_base_nand(); debugX(1, "dev_ready\n"); return readl(&nand->nfstat) & 0x01; }
int board_nand_init(struct nand_chip *nand) { u_int32_t cfg; u_int8_t tacls, twrph0, twrph1; struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); struct s3c2410_nand *nand_reg = s3c2410_get_base_nand(); debugX(1, "board_nand_init()\n"); writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon); /* initialize hardware */ #if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING) tacls = CONFIG_S3C24XX_TACLS; twrph0 = CONFIG_S3C24XX_TWRPH0; twrph1 = CONFIG_S3C24XX_TWRPH1; #else tacls = 4; twrph0 = 8; twrph1 = 8; #endif cfg = S3C2410_NFCONF_EN; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); writel(cfg, &nand_reg->nfconf); /* initialize nand_chip data structure */ nand->IO_ADDR_R = (void *)&nand_reg->nfdata; nand->IO_ADDR_W = (void *)&nand_reg->nfdata; nand->select_chip = NULL; /* read_buf and write_buf are default */ /* read_byte and write_byte are default */ #ifdef CONFIG_NAND_SPL nand->read_buf = nand_read_buf; #endif /* hwcontrol always must be implemented */ nand->cmd_ctrl = s3c2410_hwcontrol; nand->dev_ready = s3c2410_dev_ready; #ifdef CONFIG_S3C2410_NAND_HWECC nand->ecc.hwctl = s3c2410_nand_enable_hwecc; nand->ecc.calculate = s3c2410_nand_calculate_ecc; nand->ecc.correct = s3c2410_nand_correct_data; nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; #else nand->ecc.mode = NAND_ECC_SOFT; #endif #ifdef CONFIG_S3C2410_NAND_BBT nand->options = NAND_USE_FLASH_BBT; #else nand->options = 0; #endif debugX(1, "end of nand_init\n"); return 0; }
static void s3c2410_udc_epn(int ep) { struct usb_endpoint_instance *endpoint; struct urb *urb; u32 ep_csr1; if (ep >= S3C2410_UDC_NUM_ENDPOINTS) return; endpoint = &udc_device->bus->endpoint_array[ep]; S3C2410_UDC_SETIX(ep); if (endpoint->endpoint_address & USB_DIR_IN) { /* IN transfer (device to host) */ ep_csr1 = inl(S3C2410_UDC_IN_CSR1_REG); debug("for ep=%u, IN_CSR1=0x%x ", ep, ep_csr1); urb = endpoint->tx_urb; if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) { /* Stall handshake */ debug("stall\n"); outl(0x00, S3C2410_UDC_IN_CSR1_REG); return; } if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && urb && urb->actual_length) { debug("completing previously send data "); usbd_tx_complete(endpoint); /* push pending data into FIFO */ if ((endpoint->last == endpoint->tx_packetSize) && (urb->actual_length - endpoint->sent - endpoint->last == 0)) { endpoint->sent += endpoint->last; /* Write 0 bytes of data (ZLP) */ debug("ZLP "); outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG); } else { /* write actual data to fifo */ debug_urb_buffer("TX_DATA", endpoint); s3c2410_write_noniso_tx_fifo(endpoint); outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG); } } debug("\n"); } else { /* OUT transfer (host to device) */ ep_csr1 = inl(S3C2410_UDC_OUT_CSR1_REG); debug("for ep=%u, OUT_CSR1=0x%x ", ep, ep_csr1); urb = endpoint->rcv_urb; if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) { /* Stall handshake */ debugX("SENT STALL\n"); outl(0x00, S3C2410_UDC_IN_CSR1_REG); return; } if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && urb) { /* Read pending data from fifo */ u32 fifo_count = fifo_count_out(); int is_last = 0; u32 i, urb_avail = urb->buffer_length - urb->actual_length; u8 *cp = urb->buffer + urb->actual_length; if (fifo_count < endpoint->rcv_packetSize) is_last = 1; debug("fifo_count=%u is_last=%d, urb_avail=%u\n", fifo_count, is_last, urb_avail); if (fifo_count < urb_avail) urb_avail = fifo_count; for (i = 0; i < urb_avail; i++) *cp++ = inb(ep_fifo_reg[ep]); /* if (is_last) */ /* * Once the MCU reads the packet from FIFO, * this bit should be cleared */ #ifndef AUTO_CLEAR outl(ep_csr1 & ~S3C2410_UDC_OCSR1_PKTRDY, S3C2410_UDC_OUT_CSR1_REG); #endif usbd_rcv_complete(endpoint, urb_avail, 0); /* FIXME is there a better way to notify that, * we have got data */ usbd_device_event_irq(udc_device, DEVICE_FUNCTION_PRIVATE, 0); } } urb = endpoint->rcv_urb; }