1/* 2 * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. 3 * 4 * This software is licensed under the terms of the GNU General Public 5 * License version 2, as published by the Free Software Foundation, and 6 * may be copied, distributed, and modified under those terms. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14#include <linux/module.h> 15#include <linux/kernel.h> 16#include <linux/mm.h> 17#include <linux/uaccess.h> 18#include <linux/fs.h> 19#include <linux/sched.h> 20#include <linux/slab.h> 21 22#include <linux/mmc/core.h> 23#include <linux/mmc/card.h> 24#include <linux/mmc/sdio_func.h> 25 26#include <linux/firmware.h> 27 28#include "gdm_sdio.h" 29#include "sdio_boot.h" 30 31#define TYPE_A_HEADER_SIZE 4 32#define TYPE_A_LOOKAHEAD_SIZE 16 33#define YMEM0_SIZE 0x8000 /* 32kbytes */ 34#define DOWNLOAD_SIZE (YMEM0_SIZE - TYPE_A_HEADER_SIZE) 35 36#define FW_DIR "gdm72xx/" 37#define FW_KRN "gdmskrn.bin" 38#define FW_RFS "gdmsrfs.bin" 39 40static u8 *tx_buf; 41 42static int ack_ready(struct sdio_func *func) 43{ 44 unsigned long wait = jiffies + HZ; 45 u8 val; 46 int ret; 47 48 while (time_before(jiffies, wait)) { 49 val = sdio_readb(func, 0x13, &ret); 50 if (val & 0x01) 51 return 1; 52 schedule(); 53 } 54 55 return 0; 56} 57 58static int download_image(struct sdio_func *func, const char *img_name) 59{ 60 int ret = 0, len, pno; 61 u8 *buf = tx_buf; 62 loff_t pos = 0; 63 int img_len; 64 const struct firmware *firm; 65 66 ret = request_firmware(&firm, img_name, &func->dev); 67 if (ret < 0) { 68 dev_err(&func->dev, 69 "requesting firmware %s failed with error %d\n", 70 img_name, ret); 71 return ret; 72 } 73 74 buf = kmalloc(DOWNLOAD_SIZE + TYPE_A_HEADER_SIZE, GFP_KERNEL); 75 if (!buf) 76 return -ENOMEM; 77 78 img_len = firm->size; 79 80 if (img_len <= 0) { 81 ret = -1; 82 goto out; 83 } 84 85 pno = 0; 86 while (img_len > 0) { 87 if (img_len > DOWNLOAD_SIZE) { 88 len = DOWNLOAD_SIZE; 89 buf[3] = 0; 90 } else { 91 len = img_len; /* the last packet */ 92 buf[3] = 2; 93 } 94 95 buf[0] = len & 0xff; 96 buf[1] = (len >> 8) & 0xff; 97 buf[2] = (len >> 16) & 0xff; 98 99 memcpy(buf+TYPE_A_HEADER_SIZE, firm->data + pos, len); 100 ret = sdio_memcpy_toio(func, 0, buf, len + TYPE_A_HEADER_SIZE); 101 if (ret < 0) { 102 dev_err(&func->dev, 103 "send image error: packet number = %d ret = %d\n", 104 pno, ret); 105 goto out; 106 } 107 108 if (buf[3] == 2) /* The last packet */ 109 break; 110 if (!ack_ready(func)) { 111 ret = -EIO; 112 dev_err(&func->dev, "Ack is not ready.\n"); 113 goto out; 114 } 115 ret = sdio_memcpy_fromio(func, buf, 0, TYPE_A_LOOKAHEAD_SIZE); 116 if (ret < 0) { 117 dev_err(&func->dev, 118 "receive ack error: packet number = %d ret = %d\n", 119 pno, ret); 120 goto out; 121 } 122 sdio_writeb(func, 0x01, 0x13, &ret); 123 sdio_writeb(func, 0x00, 0x10, &ret); /* PCRRT */ 124 125 img_len -= DOWNLOAD_SIZE; 126 pos += DOWNLOAD_SIZE; 127 pno++; 128 } 129 130out: 131 kfree(buf); 132 return ret; 133} 134 135int sdio_boot(struct sdio_func *func) 136{ 137 int ret; 138 const char *krn_name = FW_DIR FW_KRN; 139 const char *rfs_name = FW_DIR FW_RFS; 140 141 tx_buf = kmalloc(YMEM0_SIZE, GFP_KERNEL); 142 if (!tx_buf) 143 return -ENOMEM; 144 145 ret = download_image(func, krn_name); 146 if (ret) 147 goto restore_fs; 148 dev_info(&func->dev, "GCT: Kernel download success.\n"); 149 150 ret = download_image(func, rfs_name); 151 if (ret) 152 goto restore_fs; 153 dev_info(&func->dev, "GCT: Filesystem download success.\n"); 154 155restore_fs: 156 kfree(tx_buf); 157 return ret; 158} 159