060-ssb-add-serial-flash-driver.patch 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. --- a/drivers/ssb/Kconfig
  2. +++ b/drivers/ssb/Kconfig
  3. @@ -139,7 +139,7 @@ config SSB_DRIVER_MIPS
  4. config SSB_SFLASH
  5. bool "SSB serial flash support"
  6. - depends on SSB_DRIVER_MIPS && BROKEN
  7. + depends on SSB_DRIVER_MIPS
  8. default y
  9. # Assumption: We are on embedded, if we compile the MIPS core.
  10. --- a/drivers/ssb/driver_chipcommon_sflash.c
  11. +++ b/drivers/ssb/driver_chipcommon_sflash.c
  12. @@ -1,18 +1,395 @@
  13. /*
  14. * Sonics Silicon Backplane
  15. * ChipCommon serial flash interface
  16. + * Copyright 2011, Jonas Gorski <[email protected]>
  17. + * Copyright 2011, 2012, Hauke Mehrtens <[email protected]>
  18. + * Copyright 2010, Broadcom Corporation
  19. *
  20. * Licensed under the GNU/GPL. See COPYING for details.
  21. */
  22. +#include <linux/platform_device.h>
  23. +#include <linux/delay.h>
  24. #include <linux/ssb/ssb.h>
  25. +#include <linux/ssb/ssb_driver_chipcommon.h>
  26. #include "ssb_private.h"
  27. -/* Initialize serial flash access */
  28. -int ssb_sflash_init(struct ssb_chipcommon *cc)
  29. +#define NUM_RETRIES 3
  30. +
  31. +static struct resource ssb_sflash_resource = {
  32. + .name = "ssb_sflash",
  33. + .start = SSB_FLASH2,
  34. + .end = 0,
  35. + .flags = IORESOURCE_MEM | IORESOURCE_READONLY,
  36. +};
  37. +
  38. +struct platform_device ssb_sflash_dev = {
  39. + .name = "bcm47xx-sflash",
  40. + .resource = &ssb_sflash_resource,
  41. + .num_resources = 1,
  42. +};
  43. +
  44. +struct ssb_sflash_tbl_e {
  45. + char *name;
  46. + u32 id;
  47. + u32 blocksize;
  48. + u16 numblocks;
  49. +};
  50. +
  51. +static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
  52. + { "M25P20", 0x11, 0x10000, 4, },
  53. + { "M25P40", 0x12, 0x10000, 8, },
  54. +
  55. + { "M25P16", 0x14, 0x10000, 32, },
  56. + { "M25P32", 0x14, 0x10000, 64, },
  57. + { "M25P64", 0x16, 0x10000, 128, },
  58. + { "M25FL128", 0x17, 0x10000, 256, },
  59. + { 0 },
  60. +};
  61. +
  62. +static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
  63. + { "SST25WF512", 1, 0x1000, 16, },
  64. + { "SST25VF512", 0x48, 0x1000, 16, },
  65. + { "SST25WF010", 2, 0x1000, 32, },
  66. + { "SST25VF010", 0x49, 0x1000, 32, },
  67. + { "SST25WF020", 3, 0x1000, 64, },
  68. + { "SST25VF020", 0x43, 0x1000, 64, },
  69. + { "SST25WF040", 4, 0x1000, 128, },
  70. + { "SST25VF040", 0x44, 0x1000, 128, },
  71. + { "SST25VF040B", 0x8d, 0x1000, 128, },
  72. + { "SST25WF080", 5, 0x1000, 256, },
  73. + { "SST25VF080B", 0x8e, 0x1000, 256, },
  74. + { "SST25VF016", 0x41, 0x1000, 512, },
  75. + { "SST25VF032", 0x4a, 0x1000, 1024, },
  76. + { "SST25VF064", 0x4b, 0x1000, 2048, },
  77. + { 0 },
  78. +};
  79. +
  80. +static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
  81. + { "AT45DB011", 0xc, 256, 512, },
  82. + { "AT45DB021", 0x14, 256, 1024, },
  83. + { "AT45DB041", 0x1c, 256, 2048, },
  84. + { "AT45DB081", 0x24, 256, 4096, },
  85. + { "AT45DB161", 0x2c, 512, 4096, },
  86. + { "AT45DB321", 0x34, 512, 8192, },
  87. + { "AT45DB642", 0x3c, 1024, 8192, },
  88. + { 0 },
  89. +};
  90. +
  91. +static void ssb_sflash_cmd(struct ssb_chipcommon *chipco, u32 opcode)
  92. +{
  93. + int i;
  94. + chipco_write32(chipco, SSB_CHIPCO_FLASHCTL,
  95. + SSB_CHIPCO_FLASHCTL_START | opcode);
  96. + for (i = 0; i < 1000; i++) {
  97. + if (!(chipco_read32(chipco, SSB_CHIPCO_FLASHCTL) &
  98. + SSB_CHIPCO_FLASHCTL_BUSY))
  99. + return;
  100. + cpu_relax();
  101. + }
  102. + pr_err("SFLASH control command failed (timeout)!\n");
  103. +}
  104. +
  105. +static void ssb_sflash_write_u8(struct ssb_chipcommon *chipco, u32 offset, u8 byte)
  106. +{
  107. + chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, offset);
  108. + chipco_write32(chipco, SSB_CHIPCO_FLASHDATA, byte);
  109. +}
  110. +
  111. +/* Read len bytes starting at offset into buf. Returns number of bytes read. */
  112. +static int ssb_sflash_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
  113. +{
  114. + u8 *from, *to;
  115. + u32 cnt, i;
  116. + struct ssb_chipcommon *chipco = dev->scc;
  117. +
  118. + if (!len)
  119. + return 0;
  120. +
  121. + if ((offset + len) > chipco->sflash.size)
  122. + return -EINVAL;
  123. +
  124. + if ((len >= 4) && (offset & 3))
  125. + cnt = 4 - (offset & 3);
  126. + else if ((len >= 4) && ((u32)buf & 3))
  127. + cnt = 4 - ((u32)buf & 3);
  128. + else
  129. + cnt = len;
  130. +
  131. + from = (u8 *)KSEG0ADDR(SSB_FLASH2 + offset);
  132. +
  133. + to = (u8 *)buf;
  134. +
  135. + if (cnt < 4) {
  136. + for (i = 0; i < cnt; i++) {
  137. + *to = readb(from);
  138. + from++;
  139. + to++;
  140. + }
  141. + return cnt;
  142. + }
  143. +
  144. + while (cnt >= 4) {
  145. + *(u32 *)to = readl(from);
  146. + from += 4;
  147. + to += 4;
  148. + cnt -= 4;
  149. + }
  150. +
  151. + return len - cnt;
  152. +}
  153. +
  154. +/* Poll for command completion. Returns zero when complete. */
  155. +static int ssb_sflash_poll(struct bcm47xx_sflash *dev, u32 offset)
  156. {
  157. - pr_err("Serial flash support is not implemented yet!\n");
  158. + struct ssb_chipcommon *chipco = dev->scc;
  159. +
  160. + if (offset >= chipco->sflash.size)
  161. + return -22;
  162. +
  163. + switch (chipco->capabilities & SSB_CHIPCO_CAP_FLASHT) {
  164. + case SSB_CHIPCO_FLASHT_STSER:
  165. + /* Check for ST Write In Progress bit */
  166. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_RDSR);
  167. + return chipco_read32(chipco, SSB_CHIPCO_FLASHDATA)
  168. + & SSB_CHIPCO_FLASHDATA_ST_WIP;
  169. + case SSB_CHIPCO_FLASHT_ATSER:
  170. + /* Check for Atmel Ready bit */
  171. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_STATUS);
  172. + return !(chipco_read32(chipco, SSB_CHIPCO_FLASHDATA)
  173. + & SSB_CHIPCO_FLASHDATA_AT_READY);
  174. + }
  175. +
  176. + return 0;
  177. +}
  178. +
  179. +
  180. +static int sflash_st_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
  181. + const u8 *buf)
  182. +{
  183. + int written = 1;
  184. + struct ssb_chipcommon *chipco = dev->scc;
  185. +
  186. + /* Enable writes */
  187. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_WREN);
  188. + ssb_sflash_write_u8(chipco, offset, *buf++);
  189. + /* Issue a page program with CSA bit set */
  190. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_CSA | SSB_CHIPCO_FLASHCTL_ST_PP);
  191. + offset++;
  192. + len--;
  193. + while (len > 0) {
  194. + if ((offset & 255) == 0) {
  195. + /* Page boundary, poll droping cs and return */
  196. + chipco_write32(chipco, SSB_CHIPCO_FLASHCTL, 0);
  197. + udelay(1);
  198. + if (!ssb_sflash_poll(dev, offset)) {
  199. + /* Flash rejected command */
  200. + return -EAGAIN;
  201. + }
  202. + return written;
  203. + } else {
  204. + /* Write single byte */
  205. + ssb_sflash_cmd(chipco,
  206. + SSB_CHIPCO_FLASHCTL_ST_CSA |
  207. + *buf++);
  208. + }
  209. + written++;
  210. + offset++;
  211. + len--;
  212. + }
  213. + /* All done, drop cs & poll */
  214. + chipco_write32(chipco, SSB_CHIPCO_FLASHCTL, 0);
  215. + udelay(1);
  216. + if (!ssb_sflash_poll(dev, offset)) {
  217. + /* Flash rejected command */
  218. + return -EAGAIN;
  219. + }
  220. + return written;
  221. +}
  222. +
  223. +static int sflash_at_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
  224. + const u8 *buf)
  225. +{
  226. + struct ssb_chipcommon *chipco = dev->scc;
  227. + u32 page, byte, mask;
  228. + int ret = 0;
  229. +
  230. + mask = dev->blocksize - 1;
  231. + page = (offset & ~mask) << 1;
  232. + byte = offset & mask;
  233. + /* Read main memory page into buffer 1 */
  234. + if (byte || (len < dev->blocksize)) {
  235. + int i = 100;
  236. + chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, page);
  237. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD);
  238. + /* 250 us for AT45DB321B */
  239. + while (i > 0 && ssb_sflash_poll(dev, offset)) {
  240. + udelay(10);
  241. + i--;
  242. + }
  243. + BUG_ON(!ssb_sflash_poll(dev, offset));
  244. + }
  245. + /* Write into buffer 1 */
  246. + for (ret = 0; (ret < (int)len) && (byte < dev->blocksize); ret++) {
  247. + ssb_sflash_write_u8(chipco, byte++, *buf++);
  248. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE);
  249. + }
  250. + /* Write buffer 1 into main memory page */
  251. + chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, page);
  252. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_BUF1_PROGRAM);
  253. +
  254. + return ret;
  255. +}
  256. +
  257. +/* Write len bytes starting at offset into buf. Returns number of bytes
  258. + * written. Caller should poll for completion.
  259. + */
  260. +static int ssb_sflash_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
  261. + const u8 *buf)
  262. +{
  263. + int ret = 0, tries = NUM_RETRIES;
  264. + struct ssb_chipcommon *chipco = dev->scc;
  265. +
  266. + if (!len)
  267. + return 0;
  268. +
  269. + if ((offset + len) > chipco->sflash.size)
  270. + return -EINVAL;
  271. +
  272. + switch (chipco->capabilities & SSB_CHIPCO_CAP_FLASHT) {
  273. + case SSB_CHIPCO_FLASHT_STSER:
  274. + do {
  275. + ret = sflash_st_write(dev, offset, len, buf);
  276. + tries--;
  277. + } while (ret == -EAGAIN && tries > 0);
  278. +
  279. + if (ret == -EAGAIN && tries == 0) {
  280. + pr_info("ST Flash rejected write\n");
  281. + ret = -EIO;
  282. + }
  283. + break;
  284. + case SSB_CHIPCO_FLASHT_ATSER:
  285. + ret = sflash_at_write(dev, offset, len, buf);
  286. + break;
  287. + }
  288. +
  289. + return ret;
  290. +}
  291. +
  292. +/* Erase a region. Returns number of bytes scheduled for erasure.
  293. + * Caller should poll for completion.
  294. + */
  295. +static int ssb_sflash_erase(struct bcm47xx_sflash *dev, u32 offset)
  296. +{
  297. + struct ssb_chipcommon *chipco = dev->scc;
  298. +
  299. + if (offset >= chipco->sflash.size)
  300. + return -EINVAL;
  301. +
  302. + switch (chipco->capabilities & SSB_CHIPCO_CAP_FLASHT) {
  303. + case SSB_CHIPCO_FLASHT_STSER:
  304. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_WREN);
  305. + chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, offset);
  306. + /* Newer flashes have "sub-sectors" which can be erased independently
  307. + * with a new command: ST_SSE. The ST_SE command erases 64KB just as
  308. + * before.
  309. + */
  310. + if (dev->blocksize < (64 * 1024))
  311. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_SSE);
  312. + else
  313. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_SE);
  314. + return dev->blocksize;
  315. + case SSB_CHIPCO_FLASHT_ATSER:
  316. + chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, offset << 1);
  317. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE);
  318. + return dev->blocksize;
  319. + }
  320. +
  321. + return 0;
  322. +}
  323. +
  324. +/* Initialize serial flash achipcoess */
  325. +int ssb_sflash_init(struct ssb_chipcommon *chipco)
  326. +{
  327. + struct bcm47xx_sflash *sflash = &chipco->sflash;
  328. + const struct ssb_sflash_tbl_e *e;
  329. + u32 id, id2;
  330. +
  331. + switch (chipco->capabilities & SSB_CHIPCO_CAP_FLASHT) {
  332. + case SSB_CHIPCO_FLASHT_STSER:
  333. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_DP);
  334. +
  335. + chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, 0);
  336. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_RES);
  337. + id = chipco_read32(chipco, SSB_CHIPCO_FLASHDATA);
  338. +
  339. + chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, 1);
  340. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_RES);
  341. + id2 = chipco_read32(chipco, SSB_CHIPCO_FLASHDATA);
  342. +
  343. + switch (id) {
  344. + case 0xbf:
  345. + for (e = ssb_sflash_sst_tbl; e->name; e++) {
  346. + if (e->id == id2)
  347. + break;
  348. + }
  349. + break;
  350. + case 0x13:
  351. + return -ENOTSUPP;
  352. + default:
  353. + for (e = ssb_sflash_st_tbl; e->name; e++) {
  354. + if (e->id == id)
  355. + break;
  356. + }
  357. + break;
  358. + }
  359. + if (!e->name) {
  360. + pr_err("Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n", id, id2);
  361. + return -ENOTSUPP;
  362. + }
  363. +
  364. + break;
  365. + case SSB_CHIPCO_FLASHT_ATSER:
  366. + ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_STATUS);
  367. + id = chipco_read32(chipco, SSB_CHIPCO_FLASHDATA) & 0x3c;
  368. +
  369. + for (e = ssb_sflash_at_tbl; e->name; e++) {
  370. + if (e->id == id)
  371. + break;
  372. + }
  373. + if (!e->name) {
  374. + pr_err("Unsupported Atmel serial flash (id: 0x%X)\n", id);
  375. + return -ENOTSUPP;
  376. + }
  377. +
  378. + break;
  379. + default:
  380. + pr_err("Unsupported flash type\n");
  381. + return -ENOTSUPP;
  382. + }
  383. +
  384. + sflash->window = SSB_FLASH2;
  385. + sflash->blocksize = e->blocksize;
  386. + sflash->numblocks = e->numblocks;
  387. + sflash->size = sflash->blocksize * sflash->numblocks;
  388. + sflash->present = true;
  389. + sflash->read = ssb_sflash_read;
  390. + sflash->poll = ssb_sflash_poll;
  391. + sflash->write = ssb_sflash_write;
  392. + sflash->erase = ssb_sflash_erase;
  393. + sflash->type = BCM47XX_SFLASH_SSB;
  394. + sflash->scc = chipco;
  395. +
  396. + pr_info("Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
  397. + e->name, sflash->size / 1024, sflash->blocksize,
  398. + sflash->numblocks);
  399. +
  400. + /* Prepare platform device, but don't register it yet. It's too early,
  401. + * malloc (required by device_private_init) is not available yet. */
  402. + ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
  403. + sflash->size;
  404. + ssb_sflash_dev.dev.platform_data = sflash;
  405. - return -ENOTSUPP;
  406. + return 0;
  407. }
  408. --- a/drivers/ssb/main.c
  409. +++ b/drivers/ssb/main.c
  410. @@ -19,6 +19,7 @@
  411. #include <linux/ssb/ssb_driver_gige.h>
  412. #include <linux/dma-mapping.h>
  413. #include <linux/pci.h>
  414. +#include <linux/platform_device.h>
  415. #include <linux/mmc/sdio_func.h>
  416. #include <linux/slab.h>
  417. @@ -540,6 +541,15 @@ static int ssb_devices_register(struct s
  418. dev_idx++;
  419. }
  420. +#ifdef CONFIG_SSB_SFLASH
  421. + if (bus->chipco.sflash.present) {
  422. + err = platform_device_register(&ssb_sflash_dev);
  423. + if (err)
  424. + ssb_printk(KERN_ERR PFX
  425. + "Error registering serial flash\n");
  426. + }
  427. +#endif
  428. +
  429. return 0;
  430. error:
  431. /* Unwind the already registered devices. */
  432. --- a/drivers/ssb/ssb_private.h
  433. +++ b/drivers/ssb/ssb_private.h
  434. @@ -220,6 +220,7 @@ extern u32 ssb_chipco_watchdog_timer_set
  435. /* driver_chipcommon_sflash.c */
  436. #ifdef CONFIG_SSB_SFLASH
  437. int ssb_sflash_init(struct ssb_chipcommon *cc);
  438. +extern struct platform_device ssb_sflash_dev;
  439. #else
  440. static inline int ssb_sflash_init(struct ssb_chipcommon *cc)
  441. {
  442. --- a/include/linux/ssb/ssb_driver_chipcommon.h
  443. +++ b/include/linux/ssb/ssb_driver_chipcommon.h
  444. @@ -13,6 +13,8 @@
  445. * Licensed under the GPL version 2. See COPYING for details.
  446. */
  447. +#include <linux/mtd/bcm47xx_sflash.h>
  448. +
  449. /** ChipCommon core registers. **/
  450. #define SSB_CHIPCO_CHIPID 0x0000
  451. @@ -121,6 +123,17 @@
  452. #define SSB_CHIPCO_FLASHCTL_BUSY SSB_CHIPCO_FLASHCTL_START
  453. #define SSB_CHIPCO_FLASHADDR 0x0044
  454. #define SSB_CHIPCO_FLASHDATA 0x0048
  455. +/* Status register bits for ST flashes */
  456. +#define SSB_CHIPCO_FLASHDATA_ST_WIP 0x01 /* Write In Progress */
  457. +#define SSB_CHIPCO_FLASHDATA_ST_WEL 0x02 /* Write Enable Latch */
  458. +#define SSB_CHIPCO_FLASHDATA_ST_BP_MASK 0x1c /* Block Protect */
  459. +#define SSB_CHIPCO_FLASHDATA_ST_BP_SHIFT 2
  460. +#define SSB_CHIPCO_FLASHDATA_ST_SRWD 0x80 /* Status Register Write Disable */
  461. +/* Status register bits for Atmel flashes */
  462. +#define SSB_CHIPCO_FLASHDATA_AT_READY 0x80
  463. +#define SSB_CHIPCO_FLASHDATA_AT_MISMATCH 0x40
  464. +#define SSB_CHIPCO_FLASHDATA_AT_ID_MASK 0x38
  465. +#define SSB_CHIPCO_FLASHDATA_AT_ID_SHIFT 3
  466. #define SSB_CHIPCO_BCAST_ADDR 0x0050
  467. #define SSB_CHIPCO_BCAST_DATA 0x0054
  468. #define SSB_CHIPCO_GPIOPULLUP 0x0058 /* Rev >= 20 only */
  469. @@ -504,7 +517,7 @@
  470. #define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */
  471. #define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
  472. #define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
  473. -#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
  474. +#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00D9 /* Deep Power-down */
  475. #define SSB_CHIPCO_FLASHCTL_ST_RES 0x03AB /* Read Electronic Signature */
  476. #define SSB_CHIPCO_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
  477. #define SSB_CHIPCO_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
  478. @@ -595,6 +608,9 @@ struct ssb_chipcommon {
  479. struct ssb_chipcommon_pmu pmu;
  480. u32 ticks_per_ms;
  481. u32 max_timer_ms;
  482. +#ifdef CONFIG_SSB_SFLASH
  483. + struct bcm47xx_sflash sflash;
  484. +#endif
  485. };
  486. static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)