]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c
Merge branch 'master' into tk71
[mv-sheeva.git] / drivers / staging / westbridge / astoria / arch / arm / mach-omap2 / cyashalomap_kernel.c
diff --git a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c
new file mode 100644 (file)
index 0000000..ad0c61d
--- /dev/null
@@ -0,0 +1,2444 @@
+/* Cypress WestBridge OMAP3430 Kernel Hal source file (cyashalomap_kernel.c)
+## ===========================
+## Copyright (C) 2010  Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor,
+## Boston, MA  02110-1301, USA.
+## ===========================
+*/
+
+#ifdef CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL
+
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+/* include seems broken moving for patch submission
+ * #include <mach/mux.h>
+ * #include <mach/gpmc.h>
+ * #include <mach/westbridge/westbridge-omap3-pnand-hal/cyashalomap_kernel.h>
+ * #include <mach/westbridge/westbridge-omap3-pnand-hal/cyasomapdev_kernel.h>
+ * #include <mach/westbridge/westbridge-omap3-pnand-hal/cyasmemmap.h>
+ * #include <linux/westbridge/cyaserr.h>
+ * #include <linux/westbridge/cyasregs.h>
+ * #include <linux/westbridge/cyasdma.h>
+ * #include <linux/westbridge/cyasintr.h>
+ */
+#include <linux/../../arch/arm/plat-omap/include/plat/mux.h>
+#include <linux/../../arch/arm/plat-omap/include/plat/gpmc.h>
+#include "../plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyashalomap_kernel.h"
+#include "../plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyasomapdev_kernel.h"
+#include "../plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyasmemmap.h"
+#include "../../../include/linux/westbridge/cyaserr.h"
+#include "../../../include/linux/westbridge/cyasregs.h"
+#include "../../../include/linux/westbridge/cyasdma.h"
+#include "../../../include/linux/westbridge/cyasintr.h"
+
+#define HAL_REV "1.1.0"
+
+/*
+ * uncomment to enable 16bit pnand interface
+ */
+#define PNAND_16BIT_MODE
+
+/*
+ * selects one of 3 versions of pnand_lbd_read()
+ * PNAND_LBD_READ_NO_PFE - original 8/16 bit code
+ *    reads through the gpmc CONTROLLER REGISTERS
+ * ENABLE_GPMC_PF_ENGINE - USES GPMC PFE FIFO reads, in 8 bit mode,
+ *     same speed as the above
+ * PFE_LBD_READ_V2 - slightly diffrenet, performance same as above
+ */
+#define PNAND_LBD_READ_NO_PFE
+/* #define ENABLE_GPMC_PF_ENGINE */
+/* #define  PFE_LBD_READ_V2 */
+
+/*
+ * westbrige astoria ISR options to limit number of
+ * back to back DMA transfers per ISR interrupt
+ */
+#define MAX_DRQ_LOOPS_IN_ISR 4
+
+/*
+ * debug prints enabling
+ *#define DBGPRN_ENABLED
+ *#define DBGPRN_DMA_SETUP_RD
+ *#define DBGPRN_DMA_SETUP_WR
+ */
+
+
+/*
+ * For performance reasons, we handle storage endpoint transfers upto 4 KB
+ * within the HAL itself.
+ */
+ #define CYASSTORAGE_WRITE_EP_NUM      (4)
+ #define CYASSTORAGE_READ_EP_NUM       (8)
+
+/*
+ *  size of DMA packet HAL can accept from Storage API
+ *  HAL will fragment it into smaller chunks that the P port can accept
+ */
+#define CYASSTORAGE_MAX_XFER_SIZE      (2*32768)
+
+/*
+ *  P port MAX DMA packet size according to interface/ep configurartion
+ */
+#define HAL_DMA_PKT_SZ 512
+
+#define is_storage_e_p(ep) (((ep) == 2) || ((ep) == 4) || \
+                               ((ep) == 6) || ((ep) == 8))
+
+/*
+ * persistant, stores current GPMC interface cfg mode
+ */
+static uint8_t pnand_16bit;
+
+/*
+ * keep processing new WB DRQ in ISR untill all handled (performance feature)
+ */
+#define PROCESS_MULTIPLE_DRQ_IN_ISR (1)
+
+
+/*
+ * ASTORIA PNAND IF COMMANDS, CASDO - READ, CASDI - WRITE
+ */
+#define CASDO 0x05
+#define CASDI 0x85
+#define RDPAGE_B1   0x00
+#define RDPAGE_B2   0x30
+#define PGMPAGE_B1  0x80
+#define PGMPAGE_B2  0x10
+
+/*
+ * The type of DMA operation, per endpoint
+ */
+typedef enum cy_as_hal_dma_type {
+       cy_as_hal_read,
+       cy_as_hal_write,
+       cy_as_hal_none
+} cy_as_hal_dma_type;
+
+
+/*
+ * SG list halpers defined in scaterlist.h
+#define sg_is_chain(sg)                ((sg)->page_link & 0x01)
+#define sg_is_last(sg)         ((sg)->page_link & 0x02)
+#define sg_chain_ptr(sg)       \
+       ((struct scatterlist *) ((sg)->page_link & ~0x03))
+*/
+typedef struct cy_as_hal_endpoint_dma {
+       cy_bool buffer_valid;
+       uint8_t *data_p;
+       uint32_t size;
+       /*
+        * sg_list_enabled - if true use, r/w DMA transfers use sg list,
+        *              FALSE use pointer to a buffer
+        * sg_p - pointer to the owner's sg list, of there is such
+        *              (like blockdriver)
+        * dma_xfer_sz - size of the next dma xfer on P port
+        * seg_xfer_cnt -  counts xfered bytes for in current sg_list
+        *              memory segment
+        * req_xfer_cnt - total number of bytes transfered so far in
+        *              current request
+        * req_length - total request length
+        */
+       bool sg_list_enabled;
+       struct scatterlist *sg_p;
+       uint16_t dma_xfer_sz;
+       uint32_t seg_xfer_cnt;
+       uint16_t req_xfer_cnt;
+       uint16_t req_length;
+       cy_as_hal_dma_type type;
+       cy_bool pending;
+} cy_as_hal_endpoint_dma;
+
+/*
+ * The list of OMAP devices (should be one)
+ */
+static cy_as_omap_dev_kernel *m_omap_list_p;
+
+/*
+ * The callback to call after DMA operations are complete
+ */
+static cy_as_hal_dma_complete_callback callback;
+
+/*
+ * Pending data size for the endpoints
+ */
+static cy_as_hal_endpoint_dma end_points[16];
+
+/*
+ * Forward declaration
+ */
+static void cy_handle_d_r_q_interrupt(cy_as_omap_dev_kernel *dev_p);
+
+static uint16_t intr_sequence_num;
+static uint8_t intr__enable;
+spinlock_t int_lock;
+
+static u32 iomux_vma;
+static u32 csa_phy;
+
+/*
+ * gpmc I/O registers VMA
+ */
+static u32 gpmc_base;
+
+/*
+ * gpmc data VMA associated with CS4 (ASTORIA CS on GPMC)
+ */
+static u32 gpmc_data_vma;
+static u32 ndata_reg_vma;
+static u32 ncmd_reg_vma;
+static u32 naddr_reg_vma;
+
+/*
+ * fwd declarations
+ */
+static void p_nand_lbd_read(u16 col_addr, u32 row_addr, u16 count, void *buff);
+static void p_nand_lbd_write(u16 col_addr, u32 row_addr, u16 count, void *buff);
+static inline u16 __attribute__((always_inline))
+                       ast_p_nand_casdo_read(u8 reg_addr8);
+static inline void __attribute__((always_inline))
+                       ast_p_nand_casdi_write(u8 reg_addr8, u16 data);
+
+/*
+ * prints given number of omap registers
+ */
+static void cy_as_hal_print_omap_regs(char *name_prefix,
+                               u8 name_base, u32 virt_base, u16 count)
+{
+       u32 reg_val, reg_addr;
+       u16 i;
+       cy_as_hal_print_message(KERN_INFO "\n");
+       for (i = 0; i < count; i++) {
+
+               reg_addr = virt_base + (i*4);
+               /* use virtual addresses here*/
+               reg_val = __raw_readl(reg_addr);
+               cy_as_hal_print_message(KERN_INFO "%s_%d[%8.8x]=%8.8x\n",
+                                               name_prefix, name_base+i,
+                                               reg_addr, reg_val);
+       }
+}
+
+/*
+ * setMUX function for a pad + additional pad flags
+ */
+static u16 omap_cfg_reg_L(u32 pad_func_index)
+{
+       static u8 sanity_check = 1;
+
+       u32 reg_vma;
+       u16 cur_val, wr_val, rdback_val;
+
+       /*
+        * do sanity check on the omap_mux_pin_cfg[] table
+        */
+       cy_as_hal_print_message(KERN_INFO" OMAP pins user_pad cfg ");
+       if (sanity_check) {
+               if ((omap_mux_pin_cfg[END_OF_TABLE].name[0] == 'E') &&
+                       (omap_mux_pin_cfg[END_OF_TABLE].name[1] == 'N') &&
+                       (omap_mux_pin_cfg[END_OF_TABLE].name[2] == 'D')) {
+
+                       cy_as_hal_print_message(KERN_INFO
+                                       "table is good.\n");
+               } else {
+                       cy_as_hal_print_message(KERN_WARNING
+                                       "table is bad, fix it");
+               }
+               /*
+                * do it only once
+                */
+               sanity_check = 0;
+       }
+
+       /*
+        * get virtual address to the PADCNF_REG
+        */
+       reg_vma = (u32)iomux_vma + omap_mux_pin_cfg[pad_func_index].offset;
+
+       /*
+        * add additional USER PU/PD/EN flags
+        */
+       wr_val = omap_mux_pin_cfg[pad_func_index].mux_val;
+       cur_val = IORD16(reg_vma);
+
+       /*
+        * PADCFG regs 16 bit long, packed into 32 bit regs,
+        * can also be accessed as u16
+        */
+       IOWR16(reg_vma, wr_val);
+       rdback_val = IORD16(reg_vma);
+
+       /*
+        * in case if the caller wants to save the old value
+        */
+       return wr_val;
+}
+
+#define BLKSZ_4K 0x1000
+
+/*
+ * switch GPMC DATA bus mode
+ */
+void cy_as_hal_gpmc_enable_16bit_bus(bool dbus16_enabled)
+{
+       uint32_t tmp32;
+
+       /*
+        * disable gpmc CS4 operation 1st
+        */
+       tmp32 = gpmc_cs_read_reg(AST_GPMC_CS,
+                               GPMC_CS_CONFIG7) & ~GPMC_CONFIG7_CSVALID;
+       gpmc_cs_write_reg(AST_GPMC_CS, GPMC_CS_CONFIG7, tmp32);
+
+       /*
+        * GPMC NAND data bus can be 8 or 16 bit wide
+        */
+       if (dbus16_enabled) {
+               DBGPRN("enabling 16 bit bus\n");
+               gpmc_cs_write_reg(AST_GPMC_CS, GPMC_CS_CONFIG1,
+                               (GPMC_CONFIG1_DEVICETYPE(2) |
+                               GPMC_CONFIG1_WAIT_PIN_SEL(2) |
+                               GPMC_CONFIG1_DEVICESIZE_16)
+                               );
+       } else {
+               DBGPRN(KERN_INFO "enabling 8 bit bus\n");
+               gpmc_cs_write_reg(AST_GPMC_CS, GPMC_CS_CONFIG1,
+                               (GPMC_CONFIG1_DEVICETYPE(2) |
+                               GPMC_CONFIG1_WAIT_PIN_SEL(2))
+                               );
+       }
+
+       /*
+        * re-enable astoria CS operation on GPMC
+        */
+        gpmc_cs_write_reg(AST_GPMC_CS, GPMC_CS_CONFIG7,
+                       (tmp32 | GPMC_CONFIG7_CSVALID));
+
+       /*
+        *remember the state
+        */
+       pnand_16bit = dbus16_enabled;
+}
+
+static int cy_as_hal_gpmc_init(void)
+{
+       u32 tmp32;
+       int err;
+       struct gpmc_timings     timings;
+       /*
+        * get GPMC i/o registers base(already been i/o mapped
+        * in kernel, no need for separate i/o remap)
+        */
+       gpmc_base = phys_to_virt(OMAP34XX_GPMC_BASE);
+       DBGPRN(KERN_INFO "kernel has gpmc_base=%x , val@ the base=%x",
+               gpmc_base, __raw_readl(gpmc_base)
+       );
+
+       /*
+        * these are globals are full VMAs of the gpmc_base above
+        */
+       ncmd_reg_vma = GPMC_VMA(AST_GPMC_NAND_CMD);
+       naddr_reg_vma = GPMC_VMA(AST_GPMC_NAND_ADDR);
+       ndata_reg_vma = GPMC_VMA(AST_GPMC_NAND_DATA);
+
+       /*
+        * request GPMC CS for ASTORIA request
+        */
+       if (gpmc_cs_request(AST_GPMC_CS, SZ_16M, (void *)&csa_phy) < 0) {
+               cy_as_hal_print_message(KERN_ERR "error failed to request"
+                                       "ncs4 for ASTORIA\n");
+                       return -1;
+       } else {
+               DBGPRN(KERN_INFO "got phy_addr:%x for "
+                               "GPMC CS%d GPMC_CFGREG7[CS4]\n",
+                                csa_phy, AST_GPMC_CS);
+       }
+
+       /*
+        * request VM region for 4K addr space for chip select 4 phy address
+        * technically we don't need it for NAND devices, but do it anyway
+        * so that data read/write bus cycle can be triggered by reading
+        * or writing this mem region
+        */
+       if (!request_mem_region(csa_phy, BLKSZ_4K, "AST_OMAP_HAL")) {
+               err = -EBUSY;
+               cy_as_hal_print_message(KERN_ERR "error MEM region "
+                                       "request for phy_addr:%x failed\n",
+                                       csa_phy);
+                       goto out_free_cs;
+       }
+
+       /*
+        * REMAP mem region associated with our CS
+        */
+       gpmc_data_vma = (u32)ioremap_nocache(csa_phy, BLKSZ_4K);
+       if (!gpmc_data_vma) {
+               err = -ENOMEM;
+               cy_as_hal_print_message(KERN_ERR "error- ioremap()"
+                                       "for phy_addr:%x failed", csa_phy);
+
+               goto out_release_mem_region;
+       }
+       cy_as_hal_print_message(KERN_INFO "ioremap(%x) returned vma=%x\n",
+                                                       csa_phy, gpmc_data_vma);
+
+       gpmc_cs_write_reg(AST_GPMC_CS, GPMC_CS_CONFIG1,
+                                               (GPMC_CONFIG1_DEVICETYPE(2) |
+                                               GPMC_CONFIG1_WAIT_PIN_SEL(2)));
+
+       memset(&timings, 0, sizeof(timings));
+
+       /* cs timing */
+       timings.cs_on = WB_GPMC_CS_t_o_n;
+       timings.cs_wr_off = WB_GPMC_BUSCYC_t;
+       timings.cs_rd_off = WB_GPMC_BUSCYC_t;
+
+       /* adv timing */
+       timings.adv_on = WB_GPMC_ADV_t_o_n;
+       timings.adv_rd_off = WB_GPMC_BUSCYC_t;
+       timings.adv_wr_off = WB_GPMC_BUSCYC_t;
+
+       /* oe timing */
+       timings.oe_on = WB_GPMC_OE_t_o_n;
+       timings.oe_off = WB_GPMC_OE_t_o_f_f;
+       timings.access = WB_GPMC_RD_t_a_c_c;
+       timings.rd_cycle = WB_GPMC_BUSCYC_t;
+
+       /* we timing */
+       timings.we_on = WB_GPMC_WE_t_o_n;
+       timings.we_off = WB_GPMC_WE_t_o_f_f;
+       timings.wr_access = WB_GPMC_WR_t_a_c_c;
+       timings.wr_cycle = WB_GPMC_BUSCYC_t;
+
+       timings.page_burst_access = WB_GPMC_BUSCYC_t;
+       timings.wr_data_mux_bus = WB_GPMC_BUSCYC_t;
+       gpmc_cs_set_timings(AST_GPMC_CS, &timings);
+
+       cy_as_hal_print_omap_regs("GPMC_CONFIG", 1,
+                       GPMC_VMA(GPMC_CFG_REG(1, AST_GPMC_CS)), 7);
+
+       /*
+        * DISABLE cs4, NOTE GPMC REG7 is already configured
+        * at this point by gpmc_cs_request
+        */
+       tmp32 = gpmc_cs_read_reg(AST_GPMC_CS, GPMC_CS_CONFIG7) &
+                                               ~GPMC_CONFIG7_CSVALID;
+       gpmc_cs_write_reg(AST_GPMC_CS, GPMC_CS_CONFIG7, tmp32);
+
+       /*
+        * PROGRAM chip select Region, (see OMAP3430 TRM PAGE 1088)
+        */
+       gpmc_cs_write_reg(AST_GPMC_CS, GPMC_CS_CONFIG7,
+                                       (AS_CS_MASK | AS_CS_BADDR));
+
+       /*
+        * by default configure GPMC into 8 bit mode
+        * (to match astoria default mode)
+        */
+       gpmc_cs_write_reg(AST_GPMC_CS, GPMC_CS_CONFIG1,
+                                       (GPMC_CONFIG1_DEVICETYPE(2) |
+                                       GPMC_CONFIG1_WAIT_PIN_SEL(2)));
+
+       /*
+        * ENABLE astoria cs operation on GPMC
+        */
+       gpmc_cs_write_reg(AST_GPMC_CS, GPMC_CS_CONFIG7,
+                                       (tmp32 | GPMC_CONFIG7_CSVALID));
+
+       /*
+        * No method currently exists to write this register through GPMC APIs
+        * need to change WAIT2 polarity
+        */
+       tmp32 = IORD32(GPMC_VMA(GPMC_CONFIG_REG));
+       tmp32 = tmp32 | NAND_FORCE_POSTED_WRITE_B | 0x40;
+       IOWR32(GPMC_VMA(GPMC_CONFIG_REG), tmp32);
+
+       tmp32 = IORD32(GPMC_VMA(GPMC_CONFIG_REG));
+       cy_as_hal_print_message("GPMC_CONFIG_REG=0x%x\n", tmp32);
+
+       return 0;
+
+out_release_mem_region:
+       release_mem_region(csa_phy, BLKSZ_4K);
+
+out_free_cs:
+       gpmc_cs_free(AST_GPMC_CS);
+
+       return err;
+}
+
+/*
+ * west bridge astoria ISR (Interrupt handler)
+ */
+static irqreturn_t cy_astoria_int_handler(int irq,
+                               void *dev_id, struct pt_regs *regs)
+{
+       cy_as_omap_dev_kernel *dev_p;
+       uint16_t                  read_val = 0;
+       uint16_t                  mask_val = 0;
+
+       /*
+       * debug stuff, counts number of loops per one intr trigger
+       */
+       uint16_t                  drq_loop_cnt = 0;
+       uint8_t            irq_pin;
+       /*
+        * flags to watch
+        */
+       const uint16_t  sentinel = (CY_AS_MEM_P0_INTR_REG_MCUINT |
+                               CY_AS_MEM_P0_INTR_REG_MBINT |
+                               CY_AS_MEM_P0_INTR_REG_PMINT |
+                               CY_AS_MEM_P0_INTR_REG_PLLLOCKINT);
+
+       /*
+        * sample IRQ pin level (just for statistics)
+        */
+       irq_pin = __gpio_get_value(AST_INT);
+
+       /*
+        * this one just for debugging
+        */
+       intr_sequence_num++;
+
+       /*
+        * astoria device handle
+        */
+       dev_p = dev_id;
+
+       /*
+        * read Astoria intr register
+        */
+       read_val = cy_as_hal_read_register((cy_as_hal_device_tag)dev_p,
+                                               CY_AS_MEM_P0_INTR_REG);
+
+       /*
+        * save current mask value
+        */
+       mask_val = cy_as_hal_read_register((cy_as_hal_device_tag)dev_p,
+                                               CY_AS_MEM_P0_INT_MASK_REG);
+
+       DBGPRN("<1>HAL__intr__enter:_seq:%d, P0_INTR_REG:%x\n",
+                       intr_sequence_num, read_val);
+
+       /*
+        * Disable WB interrupt signal generation while we are in ISR
+        */
+       cy_as_hal_write_register((cy_as_hal_device_tag)dev_p,
+                                       CY_AS_MEM_P0_INT_MASK_REG, 0x0000);
+
+       /*
+       * this is a DRQ Interrupt
+       */
+       if (read_val & CY_AS_MEM_P0_INTR_REG_DRQINT) {
+
+               do {
+                       /*
+                        * handle DRQ interrupt
+                        */
+                       drq_loop_cnt++;
+
+                       cy_handle_d_r_q_interrupt(dev_p);
+
+                       /*
+                        * spending to much time in ISR may impact
+                        * average system performance
+                        */
+                       if (drq_loop_cnt >= MAX_DRQ_LOOPS_IN_ISR)
+                               break;
+
+               /*
+                * Keep processing if there is another DRQ int flag
+                */
+               } while (cy_as_hal_read_register((cy_as_hal_device_tag)dev_p,
+                                       CY_AS_MEM_P0_INTR_REG) &
+                                       CY_AS_MEM_P0_INTR_REG_DRQINT);
+       }
+
+       if (read_val & sentinel)
+               cy_as_intr_service_interrupt((cy_as_hal_device_tag)dev_p);
+
+       DBGPRN("<1>_hal:_intr__exit seq:%d, mask=%4.4x,"
+                       "int_pin:%d DRQ_jobs:%d\n",
+                       intr_sequence_num,
+                       mask_val,
+                       irq_pin,
+                       drq_loop_cnt);
+
+       /*
+        * re-enable WB hw interrupts
+        */
+       cy_as_hal_write_register((cy_as_hal_device_tag)dev_p,
+                                       CY_AS_MEM_P0_INT_MASK_REG, mask_val);
+
+       return IRQ_HANDLED;
+}
+
+static int cy_as_hal_configure_interrupts(void *dev_p)
+{
+       int result;
+       int irq_pin  = AST_INT;
+
+       set_irq_type(OMAP_GPIO_IRQ(irq_pin), IRQ_TYPE_LEVEL_LOW);
+
+       /*
+        * for shared IRQS must provide non NULL device ptr
+        * othervise the int won't register
+        * */
+       result = request_irq(OMAP_GPIO_IRQ(irq_pin),
+                                       (irq_handler_t)cy_astoria_int_handler,
+                                       IRQF_SHARED, "AST_INT#", dev_p);
+
+       if (result == 0) {
+               /*
+                * OMAP_GPIO_IRQ(irq_pin) - omap logical IRQ number
+                *              assigned to this interrupt
+                * OMAP_GPIO_BIT(AST_INT, GPIO_IRQENABLE1) - print status
+                *              of AST_INT GPIO IRQ_ENABLE FLAG
+                */
+               cy_as_hal_print_message(KERN_INFO"AST_INT omap_pin:"
+                               "%d assigned IRQ #%d IRQEN1=%d\n",
+                               irq_pin,
+                               OMAP_GPIO_IRQ(irq_pin),
+                               OMAP_GPIO_BIT(AST_INT, GPIO_IRQENABLE1)
+                               );
+       } else {
+               cy_as_hal_print_message("cyasomaphal: interrupt "
+                               "failed to register\n");
+               gpio_free(irq_pin);
+               cy_as_hal_print_message(KERN_WARNING
+                               "ASTORIA: can't get assigned IRQ"
+                               "%i for INT#\n", OMAP_GPIO_IRQ(irq_pin));
+       }
+
+       return result;
+}
+
+/*
+ * initialize OMAP pads/pins to user defined functions
+ */
+static void cy_as_hal_init_user_pads(user_pad_cfg_t *pad_cfg_tab)
+{
+       /*
+        * browse through the table an dinitiaze the pins
+        */
+       u32 in_level = 0;
+       u16 tmp16, mux_val;
+
+       while (pad_cfg_tab->name != NULL) {
+
+               if (gpio_request(pad_cfg_tab->pin_num, NULL) == 0) {
+
+                       pad_cfg_tab->valid = 1;
+                       mux_val = omap_cfg_reg_L(pad_cfg_tab->mux_func);
+
+                       /*
+                        * always set drv level before changing out direction
+                        */
+                       __gpio_set_value(pad_cfg_tab->pin_num,
+                                                       pad_cfg_tab->drv);
+
+                       /*
+                        * "0" - OUT, "1", input omap_set_gpio_direction
+                        * (pad_cfg_tab->pin_num, pad_cfg_tab->dir);
+                        */
+                       if (pad_cfg_tab->dir)
+                               gpio_direction_input(pad_cfg_tab->pin_num);
+                       else
+                               gpio_direction_output(pad_cfg_tab->pin_num,
+                                                       pad_cfg_tab->drv);
+
+                       /*  sample the pin  */
+                       in_level = __gpio_get_value(pad_cfg_tab->pin_num);
+
+                       cy_as_hal_print_message(KERN_INFO "configured %s to "
+                                       "OMAP pad_%d, DIR=%d "
+                                       "DOUT=%d, DIN=%d\n",
+                                       pad_cfg_tab->name,
+                                       pad_cfg_tab->pin_num,
+                                       pad_cfg_tab->dir,
+                                       pad_cfg_tab->drv,
+                                       in_level
+                       );
+               } else {
+                       /*
+                        * get the pad_mux value to check on the pin_function
+                        */
+                       cy_as_hal_print_message(KERN_INFO "couldn't cfg pin %d"
+                                       "for signal %s, its already taken\n",
+                                       pad_cfg_tab->pin_num,
+                                       pad_cfg_tab->name);
+               }
+
+               tmp16 = *(u16 *)PADCFG_VMA
+                       (omap_mux_pin_cfg[pad_cfg_tab->mux_func].offset);
+
+               cy_as_hal_print_message(KERN_INFO "GPIO_%d(PAD_CFG=%x,OE=%d"
+                       "DOUT=%d, DIN=%d IRQEN=%d)\n\n",
+                       pad_cfg_tab->pin_num, tmp16,
+                       OMAP_GPIO_BIT(pad_cfg_tab->pin_num, GPIO_OE),
+                       OMAP_GPIO_BIT(pad_cfg_tab->pin_num, GPIO_DATA_OUT),
+                       OMAP_GPIO_BIT(pad_cfg_tab->pin_num, GPIO_DATA_IN),
+                       OMAP_GPIO_BIT(pad_cfg_tab->pin_num, GPIO_IRQENABLE1)
+                       );
+
+               /*
+                * next pad_cfg deriptor
+                */
+               pad_cfg_tab++;
+       }
+
+       cy_as_hal_print_message(KERN_INFO"pads configured\n");
+}
+
+
+/*
+ * release gpios taken by the module
+ */
+static void cy_as_hal_release_user_pads(user_pad_cfg_t *pad_cfg_tab)
+{
+       while (pad_cfg_tab->name != NULL) {
+
+               if (pad_cfg_tab->valid) {
+                       gpio_free(pad_cfg_tab->pin_num);
+                       pad_cfg_tab->valid = 0;
+                       cy_as_hal_print_message(KERN_INFO "GPIO_%d "
+                                       "released from %s\n",
+                                       pad_cfg_tab->pin_num,
+                                       pad_cfg_tab->name);
+               } else {
+                       cy_as_hal_print_message(KERN_INFO "no release "
+                                       "for %s, GPIO_%d, wasn't acquired\n",
+                                       pad_cfg_tab->name,
+                                       pad_cfg_tab->pin_num);
+               }
+               pad_cfg_tab++;
+       }
+}
+
+void cy_as_hal_config_c_s_mux(void)
+{
+       /*
+        * FORCE the GPMC CS4 pin (it is in use by the  zoom system)
+        */
+       omap_cfg_reg_L(T8_OMAP3430_GPMC_n_c_s4);
+}
+EXPORT_SYMBOL(cy_as_hal_config_c_s_mux);
+
+/*
+ * inits all omap h/w
+ */
+uint32_t cy_as_hal_processor_hw_init(void)
+{
+       int i, err;
+
+       cy_as_hal_print_message(KERN_INFO "init OMAP3430 hw...\n");
+
+       iomux_vma = (u32)ioremap_nocache(
+                               (u32)CTLPADCONF_BASE_ADDR, CTLPADCONF_SIZE);
+       cy_as_hal_print_message(KERN_INFO "PADCONF_VMA=%x val=%x\n",
+                               iomux_vma, IORD32(iomux_vma));
+
+       /*
+        * remap gpio banks
+        */
+       for (i = 0; i < 6; i++) {
+               gpio_vma_tab[i].virt_addr = (u32)ioremap_nocache(
+                                       gpio_vma_tab[i].phy_addr,
+                                       gpio_vma_tab[i].size);
+
+               cy_as_hal_print_message(KERN_INFO "%s virt_addr=%x\n",
+                                       gpio_vma_tab[i].name,
+                                       (u32)gpio_vma_tab[i].virt_addr);
+       };
+
+       /*
+        * force OMAP_GPIO_126  to rleased state,
+        * will be configured to drive reset
+        */
+       gpio_free(AST_RESET);
+
+       /*
+        *same thing with AStoria CS pin
+        */
+       gpio_free(AST_CS);
+
+       /*
+        * initialize all the OMAP pads connected to astoria
+        */
+       cy_as_hal_init_user_pads(user_pad_cfg);
+
+       err = cy_as_hal_gpmc_init();
+       if (err < 0)
+               cy_as_hal_print_message(KERN_INFO"gpmc init failed:%d", err);
+
+       cy_as_hal_config_c_s_mux();
+
+       return gpmc_data_vma;
+}
+EXPORT_SYMBOL(cy_as_hal_processor_hw_init);
+
+void cy_as_hal_omap_hardware_deinit(cy_as_omap_dev_kernel *dev_p)
+{
+       /*
+        * free omap hw resources
+        */
+       if (gpmc_data_vma != 0)
+               iounmap((void *)gpmc_data_vma);
+
+       if (csa_phy != 0)
+               release_mem_region(csa_phy, BLKSZ_4K);
+
+       gpmc_cs_free(AST_GPMC_CS);
+
+       free_irq(OMAP_GPIO_IRQ(AST_INT), dev_p);
+
+       cy_as_hal_release_user_pads(user_pad_cfg);
+}
+
+/*
+ * These are the functions that are not part of the
+ * HAL layer, but are required to be called for this HAL
+ */
+
+/*
+ * Called On AstDevice LKM exit
+ */
+int stop_o_m_a_p_kernel(const char *pgm, cy_as_hal_device_tag tag)
+{
+       cy_as_omap_dev_kernel *dev_p = (cy_as_omap_dev_kernel *)tag;
+
+       /*
+        * TODO: Need to disable WB interrupt handlere 1st
+        */
+       if (0 == dev_p)
+               return 1;
+
+       cy_as_hal_print_message("<1>_stopping OMAP34xx HAL layer object\n");
+       if (dev_p->m_sig != CY_AS_OMAP_KERNEL_HAL_SIG) {
+               cy_as_hal_print_message("<1>%s: %s: bad HAL tag\n",
+                                                               pgm, __func__);
+               return 1;
+       }
+
+       /*
+        * disable interrupt
+        */
+       cy_as_hal_write_register((cy_as_hal_device_tag)dev_p,
+                       CY_AS_MEM_P0_INT_MASK_REG, 0x0000);
+
+#if 0
+       if (dev_p->thread_flag == 0) {
+               dev_p->thread_flag = 1;
+               wait_for_completion(&dev_p->thread_complete);
+               cy_as_hal_print_message("cyasomaphal:"
+                       "done cleaning thread\n");
+               cy_as_hal_destroy_sleep_channel(&dev_p->thread_sc);
+       }
+#endif
+
+       cy_as_hal_omap_hardware_deinit(dev_p);
+
+       /*
+        * Rearrange the list
+        */
+       if (m_omap_list_p == dev_p)
+               m_omap_list_p = dev_p->m_next_p;
+
+       cy_as_hal_free(dev_p);
+
+       cy_as_hal_print_message(KERN_INFO"OMAP_kernel_hal stopped\n");
+       return 0;
+}
+
+int omap_start_intr(cy_as_hal_device_tag tag)
+{
+       cy_as_omap_dev_kernel *dev_p = (cy_as_omap_dev_kernel *)tag;
+       int ret = 0;
+       const uint16_t mask = CY_AS_MEM_P0_INTR_REG_DRQINT |
+                               CY_AS_MEM_P0_INTR_REG_MBINT;
+
+       /*
+        * register for interrupts
+        */
+       ret = cy_as_hal_configure_interrupts(dev_p);
+
+       /*
+        * enable only MBox & DRQ interrupts for now
+        */
+       cy_as_hal_write_register((cy_as_hal_device_tag)dev_p,
+                               CY_AS_MEM_P0_INT_MASK_REG, mask);
+
+       return 1;
+}
+
+/*
+ * Below are the functions that communicate with the WestBridge device.
+ * These are system dependent and must be defined by the HAL layer
+ * for a given system.
+ */
+
+/*
+ * GPMC NAND command+addr write phase
+ */
+static inline void nand_cmd_n_addr(u8 cmdb1, u16 col_addr, u32 row_addr)
+{
+       /*
+        * byte order on the bus <cmd> <CA0,CA1,RA0,RA1, RA2>
+        */
+       u32 tmpa32 = ((row_addr << 16) | col_addr);
+       u8 RA2 = (u8)(row_addr >> 16);
+
+       if (!pnand_16bit) {
+               /*
+                * GPMC PNAND 8bit BUS
+                */
+               /*
+                * CMD1
+                */
+               IOWR8(ncmd_reg_vma, cmdb1);
+
+               /*
+                *pnand bus: <CA0,CA1,RA0,RA1>
+                */
+               IOWR32(naddr_reg_vma, tmpa32);
+
+               /*
+                * <RA2> , always zero
+                */
+               IOWR8(naddr_reg_vma, RA2);
+
+       } else {
+               /*
+                * GPMC PNAND 16bit BUS , in 16 bit mode CMD
+                * and ADDR sent on [d7..d0]
+                */
+               uint8_t CA0, CA1, RA0, RA1;
+               CA0 = tmpa32 & 0x000000ff;
+               CA1 = (tmpa32 >> 8) &  0x000000ff;
+               RA0 = (tmpa32 >> 16) & 0x000000ff;
+               RA1 = (tmpa32 >> 24) & 0x000000ff;
+
+               /*
+                * can't use 32 bit writes here omap will not serialize
+                * them to lower half in16 bit mode
+                */
+
+               /*
+                *pnand bus: <CMD1, CA0,CA1,RA0,RA1, RA2 (always zero)>
+                */
+               IOWR8(ncmd_reg_vma, cmdb1);
+               IOWR8(naddr_reg_vma, CA0);
+               IOWR8(naddr_reg_vma, CA1);
+               IOWR8(naddr_reg_vma, RA0);
+               IOWR8(naddr_reg_vma, RA1);
+               IOWR8(naddr_reg_vma, RA2);
+       }
+}
+
+/*
+ * spin until r/b goes high
+ */
+inline int wait_rn_b_high(void)
+{
+       u32 w_spins = 0;
+
+       /*
+        * TODO: note R/b may go low here, need to spin until high
+        * while (omap_get_gpio_datain(AST_RnB) == 0) {
+        * w_spins++;
+        * }
+        * if (OMAP_GPIO_BIT(AST_RnB, GPIO_DATA_IN)  == 0) {
+        *
+        * while (OMAP_GPIO_BIT(AST_RnB, GPIO_DATA_IN)  == 0) {
+        * w_spins++;
+        * }
+        * printk("<1>RnB=0!:%d\n",w_spins);
+        * }
+        */
+       return w_spins;
+}
+
+#ifdef ENABLE_GPMC_PF_ENGINE
+/* #define PFE_READ_DEBUG
+ * PNAND  block read with OMAP PFE enabled
+ * status: Not tested, NW, broken , etc
+ */
+static void p_nand_lbd_read(u16 col_addr, u32 row_addr, u16 count, void *buff)
+{
+       uint16_t w32cnt;
+       uint32_t *ptr32;
+       uint8_t *ptr8;
+       uint8_t  bytes_in_fifo;
+
+       /* debug vars*/
+#ifdef PFE_READ_DEBUG
+       uint32_t loop_limit;
+       uint16_t bytes_read = 0;
+#endif
+
+       /*
+        * configure the prefetch engine
+        */
+       uint32_t tmp32;
+       uint32_t pfe_status;
+
+       /*
+        * DISABLE GPMC CS4 operation 1st, this is
+        * in case engine is be already disabled
+        */
+       IOWR32(GPMC_VMA(GPMC_PREFETCH_CONTROL), 0x0);
+       IOWR32(GPMC_VMA(GPMC_PREFETCH_CONFIG1), GPMC_PREFETCH_CONFIG1_VAL);
+       IOWR32(GPMC_VMA(GPMC_PREFETCH_CONFIG2), count);
+
+#ifdef PFE_READ_DEBUG
+       tmp32 = IORD32(GPMC_VMA(GPMC_PREFETCH_CONFIG1));
+       if (tmp32 != GPMC_PREFETCH_CONFIG1_VAL) {
+               printk(KERN_INFO "<1> prefetch is CONFIG1 read val:%8.8x, != VAL written:%8.8x\n",
+                               tmp32, GPMC_PREFETCH_CONFIG1_VAL);
+               tmp32 = IORD32(GPMC_VMA(GPMC_PREFETCH_STATUS));
+               printk(KERN_INFO "<1> GPMC_PREFETCH_STATUS : %8.8x\n", tmp32);
+       }
+
+       /*
+        *sanity check 2
+        */
+       tmp32 = IORD32(GPMC_VMA(GPMC_PREFETCH_CONFIG2));
+       if (tmp32 != (count))
+               printk(KERN_INFO "<1> GPMC_PREFETCH_CONFIG2 read val:%d, "
+                               "!= VAL written:%d\n", tmp32, count);
+#endif
+
+       /*
+        * ISSUE PNAND CMD+ADDR, note gpmc puts 32b words
+        * on the bus least sig. byte 1st
+        */
+       nand_cmd_n_addr(RDPAGE_B1, col_addr, row_addr);
+
+       IOWR8(ncmd_reg_vma, RDPAGE_B2);
+
+       /*
+        * start the prefetch engine
+        */
+       IOWR32(GPMC_VMA(GPMC_PREFETCH_CONTROL), 0x1);
+
+       ptr32 = buff;
+
+       while (1) {
+               /*
+                * GPMC PFE service loop
+                */
+               do {
+                       /*
+                        * spin until PFE fetched some
+                        * PNAND bus words in the FIFO
+                        */
+                       pfe_status = IORD32(GPMC_VMA(GPMC_PREFETCH_STATUS));
+                       bytes_in_fifo = (pfe_status >> 24) & 0x7f;
+               } while (bytes_in_fifo == 0);
+
+               /* whole 32 bit words in fifo */
+               w32cnt = bytes_in_fifo >> 2;
+
+#if 0
+          /*
+               *NOTE: FIFO_PTR indicates number of NAND bus words bytes
+               *   already received in the FIFO and available to be read
+               *   by DMA or MPU whether COUNTVAL indicates number of BUS
+               *   words yet to be read from PNAND bus words
+               */
+               printk(KERN_ERR "<1> got PF_STATUS:%8.8x FIFO_PTR:%d, COUNTVAL:%d, w32cnt:%d\n",
+                                       pfe_status, bytes_in_fifo,
+                                       (pfe_status & 0x3fff), w32cnt);
+#endif
+
+               while (w32cnt--)
+                       *ptr32++ = IORD32(gpmc_data_vma);
+
+               if ((pfe_status & 0x3fff) == 0) {
+                       /*
+                        * PFE acc angine done, there still may be data leftover
+                        * in the FIFO re-read FIFO BYTE counter (check for
+                        * leftovers from 32 bit read accesses above)
+                        */
+                       bytes_in_fifo = (IORD32(
+                               GPMC_VMA(GPMC_PREFETCH_STATUS)) >> 24) & 0x7f;
+
+                       /*
+                        * NOTE we may still have one word left in the fifo
+                        * read it out
+                        */
+                       ptr8 = ptr32;
+                       switch (bytes_in_fifo) {
+
+                       case 0:
+                               /*
+                                * nothing to do we already read the
+                                * FIFO out with 32 bit accesses
+                                */
+                               break;
+                       case 1:
+                               /*
+                               * this only possible
+                               * for 8 bit pNAND only
+                               */
+                               *ptr8 = IORD8(gpmc_data_vma);
+                               break;
+
+                       case 2:
+                               /*
+                                * this one can occur in either modes
+                                */
+                               *(uint16_t *)ptr8 = IORD16(gpmc_data_vma);
+                               break;
+
+                       case 3:
+                               /*
+                                * this only possible for 8 bit pNAND only
+                                */
+                               *(uint16_t *)ptr8 = IORD16(gpmc_data_vma);
+                               ptr8 += 2;
+                               *ptr8 = IORD8(gpmc_data_vma);
+                               break;
+
+                       case 4:
+                               /*
+                                * shouldn't happen, but has been seen
+                                * in 8 bit mode
+                                */
+                               *ptr32 = IORD32(gpmc_data_vma);
+                               break;
+
+                       default:
+                               printk(KERN_ERR"<1>_error: PFE FIFO bytes leftover is not read:%d\n",
+                                                               bytes_in_fifo);
+                               break;
+                       }
+                       /*
+                        * read is completed, get out of the while(1) loop
+                        */
+                       break;
+               }
+       }
+}
+#endif
+
+#ifdef PFE_LBD_READ_V2
+/*
+ * PFE engine assisted reads with the 64 byte blocks
+ */
+static void p_nand_lbd_read(u16 col_addr, u32 row_addr, u16 count, void *buff)
+{
+       uint8_t rd_cnt;
+       uint32_t *ptr32;
+       uint8_t  *ptr8;
+       uint16_t reminder;
+       uint32_t pfe_status;
+
+       /*
+        * ISSUE PNAND CMD+ADDR
+        * note gpmc puts 32b words on the bus least sig. byte 1st
+        */
+       nand_cmd_n_addr(RDPAGE_B1, col_addr, row_addr);
+       IOWR8(ncmd_reg_vma, RDPAGE_B2);
+
+       /*
+        * setup PFE block
+        * count - OMAP number of bytes to access on pnand bus
+        */
+
+       IOWR32(GPMC_VMA(GPMC_PREFETCH_CONFIG1), GPMC_PREFETCH_CONFIG1_VAL);
+       IOWR32(GPMC_VMA(GPMC_PREFETCH_CONFIG2), count);
+       IOWR32(GPMC_VMA(GPMC_PREFETCH_CONTROL), 0x1);
+
+       ptr32 = buff;
+
+       do {
+               pfe_status = IORD32(GPMC_VMA(GPMC_PREFETCH_STATUS));
+               rd_cnt =  pfe_status >> (24+2);
+
+               while (rd_cnt--)
+                       *ptr32++ = IORD32(gpmc_data_vma);
+
+       } while (pfe_status & 0x3fff);
+
+       /*
+        * read out the leftover
+        */
+       ptr8 = ptr32;
+       rd_cnt = (IORD32(GPMC_VMA(GPMC_PREFETCH_STATUS))  >> 24) & 0x7f;
+
+       while (rd_cnt--)
+               *ptr8++ = IORD8(gpmc_data_vma);
+}
+#endif
+
+#ifdef PNAND_LBD_READ_NO_PFE
+/*
+ * Endpoint buffer read  w/o OMAP GPMC Prefetch Engine
+ * the original working code, works at max speed for 8 bit xfers
+ * for 16 bit the bus diagram has gaps
+ */
+static void p_nand_lbd_read(u16 col_addr, u32 row_addr, u16 count, void *buff)
+{
+       uint16_t w32cnt;
+       uint32_t *ptr32;
+       uint16_t *ptr16;
+       uint16_t remainder;
+
+       DBGPRN("<1> %s(): NO_PFE\n", __func__);
+
+       ptr32 = buff;
+       /* number of whole 32 bit words in the transfer */
+       w32cnt = count >> 2;
+
+       /* remainder, in bytes(0..3) */
+       remainder =  count & 03;
+
+       /*
+        * note gpmc puts 32b words on the bus least sig. byte 1st
+        */
+       nand_cmd_n_addr(RDPAGE_B1, col_addr, row_addr);
+       IOWR8(ncmd_reg_vma, RDPAGE_B2);
+
+       /*
+        * read data by 32 bit chunks
+        */
+       while (w32cnt--)
+               *ptr32++ = IORD32(ndata_reg_vma);
+
+       /*
+        * now do the remainder(it can be 0, 1, 2 or 3)
+        * same code for both 8 & 16 bit bus
+        * do 1 or 2 MORE words
+        */
+       ptr16 = (uint16_t *)ptr32;
+
+       switch (remainder) {
+       case 1:
+               /*  read one 16 bit word
+                * IN 8 BIT WE NEED TO READ even number of bytes
+                */
+       case 2:
+               *ptr16 = IORD16(ndata_reg_vma);
+               break;
+       case 3:
+               /*
+                * for 3 bytes read 2 16 bit words
+                */
+               *ptr16++ = IORD16(ndata_reg_vma);
+               *ptr16   = IORD16(ndata_reg_vma);
+               break;
+       default:
+               /*
+                * remainder is 0
+                */
+               break;
+       }
+}
+#endif
+
+/*
+ * uses LBD mode to write N bytes into astoria
+ * Status: Working, however there are 150ns idle
+ * timeafter every 2 (16 bit or 4(8 bit) bus cycles
+ */
+static void p_nand_lbd_write(u16 col_addr, u32 row_addr, u16 count, void *buff)
+{
+       uint16_t w32cnt;
+       uint16_t remainder;
+       uint8_t  *ptr8;
+       uint16_t *ptr16;
+       uint32_t *ptr32;
+
+       remainder =  count & 03;
+       w32cnt = count >> 2;
+       ptr32 = buff;
+       ptr8 = buff;
+
+       /*
+        * send: CMDB1, CA0,CA1,RA0,RA1,RA2
+        */
+       nand_cmd_n_addr(PGMPAGE_B1, col_addr, row_addr);
+
+       /*
+        * blast the data out in 32bit chunks
+        */
+       while (w32cnt--)
+               IOWR32(ndata_reg_vma, *ptr32++);
+
+       /*
+        * do the reminder if there is one
+        * same handling for both 8 & 16 bit pnand: mode
+        */
+       ptr16 = (uint16_t *)ptr32; /* do 1 or 2  words */
+
+       switch (remainder) {
+       case 1:
+               /*
+                * read one 16 bit word
+                */
+       case 2:
+               IOWR16(ndata_reg_vma, *ptr16);
+               break;
+
+       case 3:
+               /*
+                * for 3 bytes read 2 16 bit words
+                */
+               IOWR16(ndata_reg_vma, *ptr16++);
+               IOWR16(ndata_reg_vma, *ptr16);
+               break;
+       default:
+               /*
+                * reminder is 0
+                */
+               break;
+       }
+       /*
+        * finally issue a PGM cmd
+        */
+       IOWR8(ncmd_reg_vma, PGMPAGE_B2);
+}
+
+/*
+ * write Astoria register
+ */
+static inline void ast_p_nand_casdi_write(u8 reg_addr8, u16 data)
+{
+       unsigned long flags;
+       u16 addr16;
+       /*
+        * throw an error if called from multiple threads
+        */
+       static atomic_t rdreg_usage_cnt = { 0 };
+
+       /*
+        * disable interrupts
+        */
+       local_irq_save(flags);
+
+       if (atomic_read(&rdreg_usage_cnt) != 0) {
+               cy_as_hal_print_message(KERN_ERR "cy_as_omap_hal:"
+                               "* cy_as_hal_write_register usage:%d\n",
+                               atomic_read(&rdreg_usage_cnt));
+       }
+
+       atomic_inc(&rdreg_usage_cnt);
+
+       /*
+        * 2 flavors of GPMC -> PNAND  access
+        */
+       if (pnand_16bit) {
+               /*
+                *  16 BIT gpmc NAND mode
+                */
+
+               /*
+                * CMD1, CA1, CA2,
+                */
+               IOWR8(ncmd_reg_vma, 0x85);
+               IOWR8(naddr_reg_vma, reg_addr8);
+               IOWR8(naddr_reg_vma, 0x0c);
+
+               /*
+                * this should be sent on the 16 bit bus
+                */
+               IOWR16(ndata_reg_vma, data);
+       } else {
+               /*
+                * 8 bit nand mode GPMC will automatically
+                * seriallize 16bit or 32 bit writes into
+                * 8 bit onesto the lower 8 bit in LE order
+                */
+               addr16 = 0x0c00 | reg_addr8;
+
+               /*
+                * CMD1, CA1, CA2,
+                */
+               IOWR8(ncmd_reg_vma, 0x85);
+               IOWR16(naddr_reg_vma, addr16);
+               IOWR16(ndata_reg_vma, data);
+       }
+
+       /*
+        * re-enable interrupts
+        */
+       atomic_dec(&rdreg_usage_cnt);
+       local_irq_restore(flags);
+}
+
+
+/*
+ * read astoria register via pNAND interface
+ */
+static inline u16 ast_p_nand_casdo_read(u8 reg_addr8)
+{
+       u16 data;
+       u16 addr16;
+       unsigned long flags;
+       /*
+        * throw an error if called from multiple threads
+        */
+       static atomic_t wrreg_usage_cnt = { 0 };
+
+       /*
+        * disable interrupts
+        */
+       local_irq_save(flags);
+
+       if (atomic_read(&wrreg_usage_cnt) != 0) {
+               /*
+                * if it gets here ( from other threads), this function needs
+                * need spin_lock_irq save() protection
+                */
+               cy_as_hal_print_message(KERN_ERR"cy_as_omap_hal: "
+                               "cy_as_hal_write_register usage:%d\n",
+                               atomic_read(&wrreg_usage_cnt));
+       }
+       atomic_inc(&wrreg_usage_cnt);
+
+       /*
+        * 2 flavors of GPMC -> PNAND  access
+        */
+       if (pnand_16bit) {
+               /*
+                *  16 BIT gpmc NAND mode
+                *  CMD1, CA1, CA2,
+                */
+
+               IOWR8(ncmd_reg_vma, 0x05);
+               IOWR8(naddr_reg_vma, reg_addr8);
+               IOWR8(naddr_reg_vma, 0x0c);
+               IOWR8(ncmd_reg_vma, 0x00E0);
+
+               udelay(1);
+
+               /*
+                * much faster through the gPMC Register space
+                */
+               data = IORD16(ndata_reg_vma);
+       } else {
+               /*
+                *  8 BIT gpmc NAND mode
+                *  CMD1, CA1, CA2, CMD2
+                */
+               addr16 = 0x0c00 | reg_addr8;
+               IOWR8(ncmd_reg_vma, 0x05);
+               IOWR16(naddr_reg_vma, addr16);
+               IOWR8(ncmd_reg_vma, 0xE0);
+               udelay(1);
+               data = IORD16(ndata_reg_vma);
+       }
+
+       /*
+        * re-enable interrupts
+        */
+       atomic_dec(&wrreg_usage_cnt);
+       local_irq_restore(flags);
+
+       return data;
+}
+
+
+/*
+ * This function must be defined to write a register within the WestBridge
+ * device.  The addr value is the address of the register to write with
+ * respect to the base address of the WestBridge device.
+ */
+void cy_as_hal_write_register(
+                                       cy_as_hal_device_tag tag,
+                                       uint16_t addr, uint16_t data)
+{
+       ast_p_nand_casdi_write((u8)addr, data);
+}
+
+/*
+ * This function must be defined to read a register from the WestBridge
+ * device.  The addr value is the address of the register to read with
+ * respect to the base address of the WestBridge device.
+ */
+uint16_t cy_as_hal_read_register(cy_as_hal_device_tag tag, uint16_t addr)
+{
+       uint16_t data  = 0;
+
+       /*
+        * READ ASTORIA REGISTER USING CASDO
+        */
+       data = ast_p_nand_casdo_read((u8)addr);
+
+       return data;
+}
+
+/*
+ * preps Ep pointers & data counters for next packet
+ * (fragment of the request) xfer returns true if
+ * there is a next transfer, and false if all bytes in
+ * current request have been xfered
+ */
+static inline bool prep_for_next_xfer(cy_as_hal_device_tag tag, uint8_t ep)
+{
+
+       if (!end_points[ep].sg_list_enabled) {
+               /*
+                * no further transfers for non storage EPs
+                * (like EP2 during firmware download, done
+                * in 64 byte chunks)
+                */
+               if (end_points[ep].req_xfer_cnt >= end_points[ep].req_length) {
+                       DBGPRN("<1> %s():RQ sz:%d non-_sg EP:%d completed\n",
+                               __func__, end_points[ep].req_length, ep);
+
+                       /*
+                        * no more transfers, we are done with the request
+                        */
+                       return false;
+               }
+
+               /*
+                * calculate size of the next DMA xfer, corner
+                * case for non-storage EPs where transfer size
+                * is not egual N * HAL_DMA_PKT_SZ xfers
+                */
+               if ((end_points[ep].req_length - end_points[ep].req_xfer_cnt)
+               >= HAL_DMA_PKT_SZ) {
+                               end_points[ep].dma_xfer_sz = HAL_DMA_PKT_SZ;
+               } else {
+                       /*
+                        * that would be the last chunk less
+                        * than P-port max size
+                        */
+                       end_points[ep].dma_xfer_sz = end_points[ep].req_length -
+                                       end_points[ep].req_xfer_cnt;
+               }
+
+               return true;
+       }
+
+       /*
+        * for SG_list assisted dma xfers
+        * are we done with current SG ?
+        */
+       if (end_points[ep].seg_xfer_cnt ==  end_points[ep].sg_p->length) {
+               /*
+                *  was it the Last SG segment on the list ?
+                */
+               if (sg_is_last(end_points[ep].sg_p)) {
+                       DBGPRN("<1> %s: EP:%d completed,"
+                                       "%d bytes xfered\n",
+                                       __func__,
+                                       ep,
+                                       end_points[ep].req_xfer_cnt
+                       );
+
+                       return false;
+               } else {
+                       /*
+                        * There are more SG segments in current
+                        * request's sg list setup new segment
+                        */
+
+                       end_points[ep].seg_xfer_cnt = 0;
+                       end_points[ep].sg_p = sg_next(end_points[ep].sg_p);
+                       /* set data pointer for next DMA sg transfer*/
+                       end_points[ep].data_p = sg_virt(end_points[ep].sg_p);
+                       DBGPRN("<1> %s new SG:_va:%p\n\n",
+                                       __func__, end_points[ep].data_p);
+               }
+
+       }
+
+       /*
+        * for sg list xfers it will always be 512 or 1024
+        */
+       end_points[ep].dma_xfer_sz = HAL_DMA_PKT_SZ;
+
+       /*
+        * next transfer is required
+        */
+
+       return true;
+}
+
+/*
+ * Astoria DMA read request, APP_CPU reads from WB ep buffer
+ */
+static void cy_service_e_p_dma_read_request(
+                       cy_as_omap_dev_kernel *dev_p, uint8_t ep)
+{
+       cy_as_hal_device_tag tag = (cy_as_hal_device_tag)dev_p;
+       uint16_t  v, size;
+       void    *dptr;
+       uint16_t col_addr = 0x0000;
+       uint32_t row_addr = CYAS_DEV_CALC_EP_ADDR(ep);
+       uint16_t ep_dma_reg = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2;
+
+       /*
+        * get the XFER size frtom WB eP DMA REGISTER
+        */
+       v = cy_as_hal_read_register(tag, ep_dma_reg);
+
+       /*
+        * amount of data in EP buff in  bytes
+        */
+       size =  v & CY_AS_MEM_P0_E_pn_DMA_REG_COUNT_MASK;
+
+       /*
+        * memory pointer for this DMA packet xfer (sub_segment)
+        */
+       dptr = end_points[ep].data_p;
+
+       DBGPRN("<1>HAL:_svc_dma_read on EP_%d sz:%d, intr_seq:%d, dptr:%p\n",
+               ep,
+               size,
+               intr_sequence_num,
+               dptr
+       );
+
+       cy_as_hal_assert(size != 0);
+
+       if (size) {
+               /*
+                * the actual WB-->OMAP memory "soft" DMA xfer
+                */
+               p_nand_lbd_read(col_addr, row_addr, size, dptr);
+       }
+
+       /*
+        * clear DMAVALID bit indicating that the data has been read
+        */
+       cy_as_hal_write_register(tag, ep_dma_reg, 0);
+
+       end_points[ep].seg_xfer_cnt += size;
+       end_points[ep].req_xfer_cnt += size;
+
+       /*
+        *  pre-advance data pointer (if it's outside sg
+        * list it will be reset anyway
+        */
+       end_points[ep].data_p += size;
+
+       if (prep_for_next_xfer(tag, ep)) {
+               /*
+                * we have more data to read in this request,
+                * setup next dma packet due tell WB how much
+                * data we are going to xfer next
+                */
+               v = end_points[ep].dma_xfer_sz/*HAL_DMA_PKT_SZ*/ |
+                               CY_AS_MEM_P0_E_pn_DMA_REG_DMAVAL;
+               cy_as_hal_write_register(tag, ep_dma_reg, v);
+       } else {
+               end_points[ep].pending    = cy_false;
+               end_points[ep].type              = cy_as_hal_none;
+               end_points[ep].buffer_valid = cy_false;
+
+               /*
+                * notify the API that we are done with rq on this EP
+                */
+               if (callback) {
+                       DBGPRN("<1>trigg rd_dma completion cb: xfer_sz:%d\n",
+                               end_points[ep].req_xfer_cnt);
+                               callback(tag, ep,
+                                       end_points[ep].req_xfer_cnt,
+                                       CY_AS_ERROR_SUCCESS);
+               }
+       }
+}
+
+/*
+ * omap_cpu needs to transfer data to ASTORIA EP buffer
+ */
+static void cy_service_e_p_dma_write_request(
+                       cy_as_omap_dev_kernel *dev_p, uint8_t ep)
+{
+       uint16_t  addr;
+       uint16_t v  = 0;
+       uint32_t  size;
+       uint16_t col_addr = 0x0000;
+       uint32_t row_addr = CYAS_DEV_CALC_EP_ADDR(ep);
+       void    *dptr;
+
+       cy_as_hal_device_tag tag = (cy_as_hal_device_tag)dev_p;
+       /*
+        * note: size here its the size of the dma transfer could be
+        * anything > 0 && < P_PORT packet size
+        */
+       size = end_points[ep].dma_xfer_sz;
+       dptr = end_points[ep].data_p;
+
+       /*
+        * perform the soft DMA transfer, soft in this case
+        */
+       if (size)
+               p_nand_lbd_write(col_addr, row_addr, size, dptr);
+
+       end_points[ep].seg_xfer_cnt += size;
+       end_points[ep].req_xfer_cnt += size;
+       /*
+        * pre-advance data pointer
+        * (if it's outside sg list it will be reset anyway)
+        */
+       end_points[ep].data_p += size;
+
+       /*
+        * now clear DMAVAL bit to indicate we are done
+        * transferring data and that the data can now be
+        * sent via USB to the USB host, sent to storage,
+        * or used internally.
+        */
+
+       addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2;
+       cy_as_hal_write_register(tag, addr, size);
+
+       /*
+        * finally, tell the USB subsystem that the
+        * data is gone and we can accept the
+        * next request if one exists.
+        */
+       if (prep_for_next_xfer(tag, ep)) {
+               /*
+                * There is more data to go. Re-init the WestBridge DMA side
+                */
+               v = end_points[ep].dma_xfer_sz |
+                       CY_AS_MEM_P0_E_pn_DMA_REG_DMAVAL;
+               cy_as_hal_write_register(tag, addr, v);
+       } else {
+
+          end_points[ep].pending         = cy_false;
+          end_points[ep].type           = cy_as_hal_none;
+          end_points[ep].buffer_valid = cy_false;
+
+               /*
+                * notify the API that we are done with rq on this EP
+                */
+               if (callback) {
+                       /*
+                        * this callback will wake up the process that might be
+                        * sleeping on the EP which data is being transferred
+                        */
+                       callback(tag, ep,
+                                       end_points[ep].req_xfer_cnt,
+                                       CY_AS_ERROR_SUCCESS);
+               }
+       }
+}
+
+/*
+ * HANDLE DRQINT from Astoria (called in AS_Intr context
+ */
+static void cy_handle_d_r_q_interrupt(cy_as_omap_dev_kernel *dev_p)
+{
+       uint16_t v;
+       static uint8_t service_ep = 2;
+
+       /*
+        * We've got DRQ INT, read DRQ STATUS Register */
+       v = cy_as_hal_read_register((cy_as_hal_device_tag)dev_p,
+                       CY_AS_MEM_P0_DRQ);
+
+       if (v == 0) {
+#ifndef WESTBRIDGE_NDEBUG
+               cy_as_hal_print_message("stray DRQ interrupt detected\n");
+#endif
+               return;
+       }
+
+       /*
+        * Now, pick a given DMA request to handle, for now, we just
+        * go round robin.  Each bit position in the service_mask
+        * represents an endpoint from EP2 to EP15.  We rotate through
+        * each of the endpoints to find one that needs to be serviced.
+        */
+       while ((v & (1 << service_ep)) == 0) {
+
+               if (service_ep == 15)
+                       service_ep = 2;
+               else
+                       service_ep++;
+       }
+
+       if (end_points[service_ep].type == cy_as_hal_write) {
+               /*
+                * handle DMA WRITE REQUEST: app_cpu will
+                * write data into astoria EP buffer
+                */
+               cy_service_e_p_dma_write_request(dev_p, service_ep);
+       } else if (end_points[service_ep].type == cy_as_hal_read) {
+               /*
+                * handle DMA READ REQUEST: cpu will
+                * read EP buffer from Astoria
+                */
+               cy_service_e_p_dma_read_request(dev_p, service_ep);
+       }
+#ifndef WESTBRIDGE_NDEBUG
+       else
+               cy_as_hal_print_message("cyashalomap:interrupt,"
+                                       " w/o pending DMA job,"
+                                       "-check DRQ_MASK logic\n");
+#endif
+
+       /*
+        * Now bump the EP ahead, so other endpoints get
+        * a shot before the one we just serviced
+        */
+       if (end_points[service_ep].type == cy_as_hal_none) {
+               if (service_ep == 15)
+                       service_ep = 2;
+               else
+                       service_ep++;
+       }
+
+}
+
+void cy_as_hal_dma_cancel_request(cy_as_hal_device_tag tag, uint8_t ep)
+{
+       DBGPRN("cy_as_hal_dma_cancel_request on ep:%d", ep);
+       if (end_points[ep].pending)
+               cy_as_hal_write_register(tag,
+                               CY_AS_MEM_P0_EP2_DMA_REG + ep - 2, 0);
+
+       end_points[ep].buffer_valid = cy_false;
+       end_points[ep].type = cy_as_hal_none;
+}
+
+/*
+ * enables/disables SG list assisted DMA xfers for the given EP
+ * sg_list assisted XFERS can use physical addresses of mem pages in case if the
+ * xfer is performed by a h/w DMA controller rather then the CPU on P port
+ */
+void cy_as_hal_set_ep_dma_mode(uint8_t ep, bool sg_xfer_enabled)
+{
+       end_points[ep].sg_list_enabled = sg_xfer_enabled;
+       DBGPRN("<1> EP:%d sg_list assisted DMA mode set to = %d\n",
+                       ep, end_points[ep].sg_list_enabled);
+}
+EXPORT_SYMBOL(cy_as_hal_set_ep_dma_mode);
+
+/*
+ * This function must be defined to transfer a block of data to
+ * the WestBridge device.  This function can use the burst write
+ * (DMA) capabilities of WestBridge to do this, or it can just copy
+ * the data using writes.
+ */
+void cy_as_hal_dma_setup_write(cy_as_hal_device_tag tag,
+                                               uint8_t ep, void *buf,
+                                               uint32_t size, uint16_t maxsize)
+{
+       uint32_t addr = 0;
+       uint16_t v  = 0;
+
+       /*
+        * Note: "size" is the actual request size
+        * "maxsize" - is the P port fragment size
+        * No EP0 or EP1 traffic should get here
+        */
+       cy_as_hal_assert(ep != 0 && ep != 1);
+
+       /*
+        * If this asserts, we have an ordering problem.  Another DMA request
+        * is coming down before the previous one has completed.
+        */
+       cy_as_hal_assert(end_points[ep].buffer_valid == cy_false);
+       end_points[ep].buffer_valid = cy_true;
+       end_points[ep].type = cy_as_hal_write;
+       end_points[ep].pending = cy_true;
+
+       /*
+        * total length of the request
+        */
+       end_points[ep].req_length = size;
+
+       if (size >= maxsize) {
+               /*
+                * set xfer size for very 1st DMA xfer operation
+                * port max packet size ( typically 512 or 1024)
+                */
+               end_points[ep].dma_xfer_sz = maxsize;
+       } else {
+               /*
+                * smaller xfers for non-storage EPs
+                */
+               end_points[ep].dma_xfer_sz = size;
+       }
+
+       /*
+        * check the EP transfer mode uses sg_list rather then a memory buffer
+        * block devices pass it to the HAL, so the hAL could get to the real
+        * physical address for each segment and set up a DMA controller
+        * hardware ( if there is one)
+        */
+       if (end_points[ep].sg_list_enabled) {
+               /*
+                * buf -  pointer to the SG list
+                * data_p - data pointer to the 1st DMA segment
+                * seg_xfer_cnt - keeps track of N of bytes sent in current
+                *              sg_list segment
+                * req_xfer_cnt - keeps track of the total N of bytes
+                *              transferred for the request
+                */
+               end_points[ep].sg_p = buf;
+               end_points[ep].data_p = sg_virt(end_points[ep].sg_p);
+               end_points[ep].seg_xfer_cnt = 0;
+               end_points[ep].req_xfer_cnt = 0;
+
+#ifdef DBGPRN_DMA_SETUP_WR
+               DBGPRN("cyasomaphal:%s: EP:%d, buf:%p, buf_va:%p,"
+                               "req_sz:%d, maxsz:%d\n",
+                               __func__,
+                               ep,
+                               buf,
+                               end_points[ep].data_p,
+                               size,
+                               maxsize);
+#endif
+
+       } else {
+               /*
+                * setup XFER for non sg_list assisted EPs
+                */
+
+               #ifdef DBGPRN_DMA_SETUP_WR
+                       DBGPRN("<1>%s non storage or sz < 512:"
+                                       "EP:%d, sz:%d\n", __func__, ep, size);
+               #endif
+
+               end_points[ep].sg_p = NULL;
+
+               /*
+                * must be a VMA of a membuf in kernel space
+                */
+               end_points[ep].data_p = buf;
+
+               /*
+                * will keep track No of bytes xferred for the request
+                */
+               end_points[ep].req_xfer_cnt = 0;
+       }
+
+       /*
+        * Tell WB we are ready to send data on the given endpoint
+        */
+       v = (end_points[ep].dma_xfer_sz & CY_AS_MEM_P0_E_pn_DMA_REG_COUNT_MASK)
+                       | CY_AS_MEM_P0_E_pn_DMA_REG_DMAVAL;
+
+       addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2;
+
+       cy_as_hal_write_register(tag, addr, v);
+}
+
+/*
+ * This function must be defined to transfer a block of data from
+ * the WestBridge device.  This function can use the burst read
+ * (DMA) capabilities of WestBridge to do this, or it can just
+ * copy the data using reads.
+ */
+void cy_as_hal_dma_setup_read(cy_as_hal_device_tag tag,
+                                       uint8_t ep, void *buf,
+                                       uint32_t size, uint16_t maxsize)
+{
+       uint32_t addr;
+       uint16_t v;
+
+       /*
+        * Note: "size" is the actual request size
+        * "maxsize" - is the P port fragment size
+        * No EP0 or EP1 traffic should get here
+        */
+       cy_as_hal_assert(ep != 0 && ep != 1);
+
+       /*
+        * If this asserts, we have an ordering problem.
+        * Another DMA request is coming down before the
+        * previous one has completed. we should not get
+        * new requests if current is still in process
+        */
+
+       cy_as_hal_assert(end_points[ep].buffer_valid == cy_false);
+
+       end_points[ep].buffer_valid = cy_true;
+       end_points[ep].type = cy_as_hal_read;
+       end_points[ep].pending = cy_true;
+       end_points[ep].req_xfer_cnt = 0;
+       end_points[ep].req_length = size;
+
+       if (size >= maxsize) {
+               /*
+                * set xfer size for very 1st DMA xfer operation
+                * port max packet size ( typically 512 or 1024)
+                */
+               end_points[ep].dma_xfer_sz = maxsize;
+       } else {
+               /*
+                * so that we could handle small xfers on in case
+                * of non-storage EPs
+                */
+               end_points[ep].dma_xfer_sz = size;
+       }
+
+       addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2;
+
+       if (end_points[ep].sg_list_enabled) {
+               /*
+                * Handle sg-list assisted EPs
+                * seg_xfer_cnt - keeps track of N of sent packets
+                * buf - pointer to the SG list
+                * data_p - data pointer for the 1st DMA segment
+                */
+               end_points[ep].seg_xfer_cnt = 0;
+               end_points[ep].sg_p = buf;
+               end_points[ep].data_p = sg_virt(end_points[ep].sg_p);
+
+               #ifdef DBGPRN_DMA_SETUP_RD
+               DBGPRN("cyasomaphal:DMA_setup_read sg_list EP:%d, "
+                          "buf:%p, buf_va:%p, req_sz:%d, maxsz:%d\n",
+                               ep,
+                               buf,
+                               end_points[ep].data_p,
+                               size,
+                               maxsize);
+               #endif
+               v = (end_points[ep].dma_xfer_sz &
+                               CY_AS_MEM_P0_E_pn_DMA_REG_COUNT_MASK) |
+                               CY_AS_MEM_P0_E_pn_DMA_REG_DMAVAL;
+               cy_as_hal_write_register(tag, addr, v);
+       } else {
+               /*
+                * Non sg list EP passed  void *buf rather then scatterlist *sg
+                */
+               #ifdef DBGPRN_DMA_SETUP_RD
+                       DBGPRN("%s:non-sg_list EP:%d,"
+                                       "RQ_sz:%d, maxsz:%d\n",
+                                       __func__, ep, size,  maxsize);
+               #endif
+
+               end_points[ep].sg_p = NULL;
+
+               /*
+                * must be a VMA of a membuf in kernel space
+                */
+               end_points[ep].data_p = buf;
+
+               /*
+                * Program the EP DMA register for Storage endpoints only.
+                */
+               if (is_storage_e_p(ep)) {
+                       v = (end_points[ep].dma_xfer_sz &
+                                       CY_AS_MEM_P0_E_pn_DMA_REG_COUNT_MASK) |
+                                       CY_AS_MEM_P0_E_pn_DMA_REG_DMAVAL;
+                       cy_as_hal_write_register(tag, addr, v);
+               }
+       }
+}
+
+/*
+ * This function must be defined to allow the WB API to
+ * register a callback function that is called when a
+ * DMA transfer is complete.
+ */
+void cy_as_hal_dma_register_callback(cy_as_hal_device_tag tag,
+                                       cy_as_hal_dma_complete_callback cb)
+{
+       DBGPRN("<1>\n%s: WB API has registered a dma_complete callback:%x\n",
+                       __func__, (uint32_t)cb);
+       callback = cb;
+}
+
+/*
+ * This function must be defined to return the maximum size of
+ * DMA request that can be handled on the given endpoint.  The
+ * return value should be the maximum size in bytes that the DMA
+ * module can handle.
+ */
+uint32_t cy_as_hal_dma_max_request_size(cy_as_hal_device_tag tag,
+                                       cy_as_end_point_number_t ep)
+{
+       /*
+        * Storage reads and writes are always done in 512 byte blocks.
+        * So, we do the count handling within the HAL, and save on
+        * some of the data transfer delay.
+        */
+       if ((ep == CYASSTORAGE_READ_EP_NUM) ||
+       (ep == CYASSTORAGE_WRITE_EP_NUM)) {
+               /* max DMA request size HAL can handle by itself */
+               return CYASSTORAGE_MAX_XFER_SIZE;
+       } else {
+       /*
+        * For the USB - Processor endpoints, the maximum transfer
+        * size depends on the speed of USB operation. So, we use
+        * the following constant to indicate to the API that
+        * splitting of the data into chunks less that or equal to
+        * the max transfer size should be handled internally.
+        */
+
+               /* DEFINED AS 0xffffffff in cyasdma.h */
+               return CY_AS_DMA_MAX_SIZE_HW_SIZE;
+       }
+}
+
+/*
+ * This function must be defined to set the state of the WAKEUP pin
+ * on the WestBridge device.  Generally this is done via a GPIO of
+ * some type.
+ */
+cy_bool cy_as_hal_set_wakeup_pin(cy_as_hal_device_tag tag, cy_bool state)
+{
+       /*
+        * Not supported as of now.
+        */
+       return cy_false;
+}
+
+void cy_as_hal_pll_lock_loss_handler(cy_as_hal_device_tag tag)
+{
+       cy_as_hal_print_message("error: astoria PLL lock is lost\n");
+       cy_as_hal_print_message("please check the input voltage levels");
+       cy_as_hal_print_message("and clock, and restart the system\n");
+}
+
+/*
+ * Below are the functions that must be defined to provide the basic
+ * operating system services required by the API.
+ */
+
+/*
+ * This function is required by the API to allocate memory.
+ * This function is expected to work exactly like malloc().
+ */
+void *cy_as_hal_alloc(uint32_t cnt)
+{
+       return kmalloc(cnt, GFP_ATOMIC);
+}
+
+/*
+ * This function is required by the API to free memory allocated
+ * with CyAsHalAlloc().  This function is'expected to work exacly
+ * like free().
+ */
+void cy_as_hal_free(void *mem_p)
+{
+       kfree(mem_p);
+}
+
+/*
+ * Allocator that can be used in interrupt context.
+ * We have to ensure that the kmalloc call does not
+ * sleep in this case.
+ */
+void *cy_as_hal_c_b_alloc(uint32_t cnt)
+{
+       return kmalloc(cnt, GFP_ATOMIC);
+}
+
+/*
+ * This function is required to set a block of memory to a
+ * specific value.  This function is expected to work exactly
+ * like memset()
+ */
+void cy_as_hal_mem_set(void *ptr, uint8_t value, uint32_t cnt)
+{
+       memset(ptr, value, cnt);
+}
+
+/*
+ * This function is expected to create a sleep channel.
+ * The data structure that represents the sleep channel object
+ * sleep channel (which is Linux "wait_queue_head_t wq" for this paticular HAL)
+ * passed as a pointer, and allpocated by the caller
+ * (typically as a local var on the stack) "Create" word should read as
+ * "SleepOn", this func doesn't actually create anything
+ */
+cy_bool cy_as_hal_create_sleep_channel(cy_as_hal_sleep_channel *channel)
+{
+       init_waitqueue_head(&channel->wq);
+       return cy_true;
+}
+
+/*
+ * for this particular HAL it doesn't actually destroy anything
+ * since no actual sleep object is created in CreateSleepChannel()
+ * sleep channel is given by the pointer in the argument.
+ */
+cy_bool cy_as_hal_destroy_sleep_channel(cy_as_hal_sleep_channel *channel)
+{
+       return cy_true;
+}
+
+/*
+ * platform specific wakeable Sleep implementation
+ */
+cy_bool cy_as_hal_sleep_on(cy_as_hal_sleep_channel *channel, uint32_t ms)
+{
+       wait_event_interruptible_timeout(channel->wq, 0, ((ms * HZ)/1000));
+       return cy_true;
+}
+
+/*
+ * wakes up the process waiting on the CHANNEL
+ */
+cy_bool cy_as_hal_wake(cy_as_hal_sleep_channel *channel)
+{
+       wake_up_interruptible_all(&channel->wq);
+       return cy_true;
+}
+
+uint32_t cy_as_hal_disable_interrupts()
+{
+       if (0 == intr__enable)
+               ;
+
+       intr__enable++;
+       return 0;
+}
+
+void cy_as_hal_enable_interrupts(uint32_t val)
+{
+       intr__enable--;
+       if (0 == intr__enable)
+               ;
+}
+
+/*
+ * Sleep atleast 150ns, cpu dependent
+ */
+void cy_as_hal_sleep150(void)
+{
+       uint32_t i, j;
+
+       j = 0;
+       for (i = 0; i < 1000; i++)
+               j += (~i);
+}
+
+void cy_as_hal_sleep(uint32_t ms)
+{
+       cy_as_hal_sleep_channel channel;
+
+       cy_as_hal_create_sleep_channel(&channel);
+       cy_as_hal_sleep_on(&channel, ms);
+       cy_as_hal_destroy_sleep_channel(&channel);
+}
+
+cy_bool cy_as_hal_is_polling()
+{
+       return cy_false;
+}
+
+void cy_as_hal_c_b_free(void *ptr)
+{
+       cy_as_hal_free(ptr);
+}
+
+/*
+ * suppose to reinstate the astoria registers
+ * that may be clobbered in sleep mode
+ */
+void cy_as_hal_init_dev_registers(cy_as_hal_device_tag tag,
+                                       cy_bool is_standby_wakeup)
+{
+       /* specific to SPI, no implementation required */
+       (void) tag;
+       (void) is_standby_wakeup;
+}
+
+void cy_as_hal_read_regs_before_standby(cy_as_hal_device_tag tag)
+{
+       /* specific to SPI, no implementation required */
+       (void) tag;
+}
+
+cy_bool cy_as_hal_sync_device_clocks(cy_as_hal_device_tag tag)
+{
+       /*
+        * we are in asynchronous mode. so no need to handle this
+        */
+       return true;
+}
+
+/*
+ * init OMAP h/w resources
+ */
+int start_o_m_a_p_kernel(const char *pgm,
+                               cy_as_hal_device_tag *tag, cy_bool debug)
+{
+       cy_as_omap_dev_kernel *dev_p;
+       int i;
+       u16 data16[4];
+       u8 pncfg_reg;
+
+       /*
+        * No debug mode support through argument as of now
+        */
+       (void)debug;
+
+       DBGPRN(KERN_INFO"starting OMAP34xx HAL...\n");
+
+       /*
+        * Initialize the HAL level endpoint DMA data.
+        */
+       for (i = 0; i < sizeof(end_points)/sizeof(end_points[0]); i++) {
+               end_points[i].data_p = 0;
+               end_points[i].pending = cy_false;
+               end_points[i].size = 0;
+               end_points[i].type = cy_as_hal_none;
+               end_points[i].sg_list_enabled = cy_false;
+
+               /*
+                * by default the DMA transfers to/from the E_ps don't
+                * use sg_list that implies that the upper devices like
+                * blockdevice have to enable it for the E_ps in their
+                * initialization code
+                */
+       }
+
+       /*
+        * allocate memory for OMAP HAL
+        */
+       dev_p = (cy_as_omap_dev_kernel *)cy_as_hal_alloc(
+                                               sizeof(cy_as_omap_dev_kernel));
+       if (dev_p == 0) {
+               cy_as_hal_print_message("out of memory allocating OMAP"
+                                       "device structure\n");
+               return 0;
+       }
+
+       dev_p->m_sig = CY_AS_OMAP_KERNEL_HAL_SIG;
+
+       /*
+        * initialize OMAP hardware and StartOMAPKernelall gpio pins
+        */
+       dev_p->m_addr_base = (void *)cy_as_hal_processor_hw_init();
+
+       /*
+        * Now perform a hard reset of the device to have
+        * the new settings take effect
+        */
+       __gpio_set_value(AST_WAKEUP, 1);
+
+       /*
+        * do Astoria  h/w reset
+        */
+       DBGPRN(KERN_INFO"-_-_pulse -> westbridge RST pin\n");
+
+       /*
+        * NEGATIVE PULSE on RST pin
+        */
+       __gpio_set_value(AST_RESET, 0);
+       mdelay(1);
+       __gpio_set_value(AST_RESET, 1);
+       mdelay(50);
+
+       /*
+       * note AFTER reset PNAND interface is 8 bit mode
+       * so if gpmc Is configured in 8 bit mode upper half will be FF
+       */
+       pncfg_reg = ast_p_nand_casdo_read(CY_AS_MEM_PNAND_CFG);
+
+#ifdef PNAND_16BIT_MODE
+
+       /*
+        * switch to 16 bit mode, force NON-LNA LBD mode, 3 RA addr bytes
+        */
+       ast_p_nand_casdi_write(CY_AS_MEM_PNAND_CFG, 0x0001);
+
+       /*
+        * now in order to continue to talk to astoria
+        * sw OMAP GPMC into 16 bit mode as well
+        */
+       cy_as_hal_gpmc_enable_16bit_bus(cy_true);
+#else
+   /* Astoria and GPMC are already in 8 bit mode, jsut initialize PNAND_CFG */
+       ast_p_nand_casdi_write(CY_AS_MEM_PNAND_CFG, 0x0000);
+#endif
+
+   /*
+       *  NOTE: if you want to capture bus activity on the LA,
+       *  don't use printks in between the activities you want to capture.
+       *  prinks may take milliseconds, and the data of interest
+       *  will fall outside the LA capture window/buffer
+       */
+       data16[0] = ast_p_nand_casdo_read(CY_AS_MEM_CM_WB_CFG_ID);
+       data16[1] = ast_p_nand_casdo_read(CY_AS_MEM_PNAND_CFG);
+
+       if (data16[0] != 0xA200) {
+               /*
+                * astoria device is not found
+                */
+               printk(KERN_ERR "ERROR: astoria device is not found, CY_AS_MEM_CM_WB_CFG_ID ");
+               printk(KERN_ERR "read returned:%4.4X: CY_AS_MEM_PNAND_CFG:%4.4x !\n",
+                               data16[0], data16[0]);
+               goto bus_acc_error;
+       }
+
+       cy_as_hal_print_message(KERN_INFO" register access CASDO test:"
+                               "\n CY_AS_MEM_CM_WB_CFG_ID:%4.4x\n"
+                               "PNAND_CFG after RST:%4.4x\n "
+                               "CY_AS_MEM_PNAND_CFG"
+                               "after cfg_wr:%4.4x\n\n",
+                               data16[0], pncfg_reg, data16[1]);
+
+       dev_p->thread_flag = 1;
+       spin_lock_init(&int_lock);
+       dev_p->m_next_p = m_omap_list_p;
+
+       m_omap_list_p = dev_p;
+       *tag = dev_p;
+
+       cy_as_hal_configure_interrupts((void *)dev_p);
+
+       cy_as_hal_print_message(KERN_INFO"OMAP3430__hal started tag:%p"
+                               ", kernel HZ:%d\n", dev_p, HZ);
+
+       /*
+        *make processor to storage endpoints SG assisted by default
+        */
+       cy_as_hal_set_ep_dma_mode(4, true);
+       cy_as_hal_set_ep_dma_mode(8, true);
+
+       return 1;
+
+       /*
+        * there's been a NAND bus access error or
+        * astoria device is not connected
+        */
+bus_acc_error:
+       /*
+        * at this point hal tag hasn't been set yet
+        * so the device will not call omap_stop
+        */
+       cy_as_hal_omap_hardware_deinit(dev_p);
+       cy_as_hal_free(dev_p);
+       return 0;
+}
+
+#else
+/*
+ * Some compilers do not like empty C files, so if the OMAP hal is not being
+ * compiled, we compile this single function.  We do this so that for a
+ * given target HAL there are not multiple sources for the HAL functions.
+ */
+void my_o_m_a_p_kernel_hal_dummy_function(void)
+{
+}
+
+#endif