1 /* $NetBSD: spifi.c,v 1.16 2008/04/09 15:40:30 tsutsui Exp $ */
4 * Copyright (c) 2000 Tsubai Masanari. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: spifi.c,v 1.16 2008/04/09 15:40:30 tsutsui Exp $");
32 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/errno.h>
36 #include <sys/kernel.h>
37 #include <sys/queue.h>
38 #include <sys/systm.h>
40 #include <uvm/uvm_extern.h>
42 #include <dev/scsipi/scsi_all.h>
43 #include <dev/scsipi/scsi_message.h>
44 #include <dev/scsipi/scsipi_all.h>
45 #include <dev/scsipi/scsiconf.h>
47 #include <newsmips/apbus/apbusvar.h>
48 #include <newsmips/apbus/spifireg.h>
49 #include <newsmips/apbus/dmac3reg.h>
50 #include <newsmips/apbus/dmac3var.h>
52 #include <machine/adrsmap.h>
54 /* #define SPIFI_DEBUG */
57 # define DPRINTF printf
59 # define DPRINTF while (0) printf
63 TAILQ_ENTRY(spifi_scb
) chain
;
65 struct scsipi_xfer
*xs
;
66 struct scsipi_generic cmd
;
76 #define SPIFI_READ 0x80
77 #define SPIFI_DMA 0x01
81 struct scsipi_channel sc_channel
;
82 struct scsipi_adapter sc_adapter
;
84 struct spifi_reg
*sc_reg
;
85 struct spifi_scb
*sc_nexus
;
86 void *sc_dma
; /* attached DMA softc */
87 int sc_id
; /* my SCSI ID */
90 struct spifi_scb sc_scb
[16];
91 TAILQ_HEAD(, spifi_scb
) free_scb
;
92 TAILQ_HEAD(, spifi_scb
) ready_scb
;
95 #define SPIFI_SYNC_OFFSET_MAX 7
98 #define SEND_IDENTIFY 2
101 #define SPIFI_DATAOUT 0
102 #define SPIFI_DATAIN PRS_IO
103 #define SPIFI_COMMAND PRS_CD
104 #define SPIFI_STATUS (PRS_CD | PRS_IO)
105 #define SPIFI_MSGOUT (PRS_MSG | PRS_CD)
106 #define SPIFI_MSGIN (PRS_MSG | PRS_CD | PRS_IO)
108 int spifi_match(device_t
, cfdata_t
, void *);
109 void spifi_attach(device_t
, device_t
, void *);
111 void spifi_scsipi_request(struct scsipi_channel
*, scsipi_adapter_req_t
,
113 struct spifi_scb
*spifi_get_scb(struct spifi_softc
*);
114 void spifi_free_scb(struct spifi_softc
*, struct spifi_scb
*);
115 int spifi_poll(struct spifi_softc
*);
116 void spifi_minphys(struct buf
*);
118 void spifi_sched(struct spifi_softc
*);
119 int spifi_intr(void *);
120 void spifi_pmatch(struct spifi_softc
*);
122 void spifi_select(struct spifi_softc
*);
123 void spifi_sendmsg(struct spifi_softc
*, int);
124 void spifi_command(struct spifi_softc
*);
125 void spifi_data_io(struct spifi_softc
*);
126 void spifi_status(struct spifi_softc
*);
127 int spifi_done(struct spifi_softc
*);
128 void spifi_fifo_drain(struct spifi_softc
*);
129 void spifi_reset(struct spifi_softc
*);
130 void spifi_bus_reset(struct spifi_softc
*);
132 static int spifi_read_count(struct spifi_reg
*);
133 static void spifi_write_count(struct spifi_reg
*, int);
135 #define DMAC3_FASTACCESS(sc) dmac3_misc((sc)->sc_dma, DMAC3_CONF_FASTACCESS)
136 #define DMAC3_SLOWACCESS(sc) dmac3_misc((sc)->sc_dma, DMAC3_CONF_SLOWACCESS)
138 CFATTACH_DECL_NEW(spifi
, sizeof(struct spifi_softc
),
139 spifi_match
, spifi_attach
, NULL
, NULL
);
142 spifi_match(device_t parent
, cfdata_t cf
, void *aux
)
144 struct apbus_attach_args
*apa
= aux
;
146 if (strcmp(apa
->apa_name
, "spifi") == 0)
153 spifi_attach(device_t parent
, device_t self
, void *aux
)
155 struct spifi_softc
*sc
= device_private(self
);
156 struct apbus_attach_args
*apa
= aux
;
157 struct dmac3_softc
*dma
;
162 /* Initialize scbs. */
163 TAILQ_INIT(&sc
->free_scb
);
164 TAILQ_INIT(&sc
->ready_scb
);
165 for (i
= 0; i
< __arraycount(sc
->sc_scb
); i
++)
166 TAILQ_INSERT_TAIL(&sc
->free_scb
, &sc
->sc_scb
[i
], chain
);
168 sc
->sc_reg
= (struct spifi_reg
*)apa
->apa_hwbase
;
169 sc
->sc_id
= 7; /* XXX */
172 dma
= dmac3_link(apa
->apa_ctlnum
);
174 aprint_error(": cannot find slave dmac\n");
179 aprint_normal(" slot%d addr 0x%lx", apa
->apa_slotno
, apa
->apa_hwbase
);
180 aprint_normal(": SCSI ID = %d, using %s\n",
181 sc
->sc_id
, device_xname(dma
->sc_dev
));
183 dmac3_reset(sc
->sc_dma
);
185 DMAC3_SLOWACCESS(sc
);
187 DMAC3_FASTACCESS(sc
);
189 sc
->sc_adapter
.adapt_dev
= self
;
190 sc
->sc_adapter
.adapt_nchannels
= 1;
191 sc
->sc_adapter
.adapt_openings
= 7;
192 sc
->sc_adapter
.adapt_max_periph
= 1;
193 sc
->sc_adapter
.adapt_ioctl
= NULL
;
194 sc
->sc_adapter
.adapt_minphys
= minphys
;
195 sc
->sc_adapter
.adapt_request
= spifi_scsipi_request
;
197 memset(&sc
->sc_channel
, 0, sizeof(sc
->sc_channel
));
198 sc
->sc_channel
.chan_adapter
= &sc
->sc_adapter
;
199 sc
->sc_channel
.chan_bustype
= &scsi_bustype
;
200 sc
->sc_channel
.chan_channel
= 0;
201 sc
->sc_channel
.chan_ntargets
= 8;
202 sc
->sc_channel
.chan_nluns
= 8;
203 sc
->sc_channel
.chan_id
= sc
->sc_id
;
205 if (apa
->apa_slotno
== 0)
206 intr
= NEWS5000_INT0_DMAC
;
208 intr
= SLOTTOMASK(apa
->apa_slotno
);
209 apbus_intr_establish(0, intr
, 0, spifi_intr
, sc
, apa
->apa_name
,
212 config_found(self
, &sc
->sc_channel
, scsiprint
);
216 spifi_scsipi_request(struct scsipi_channel
*chan
, scsipi_adapter_req_t req
,
219 struct scsipi_xfer
*xs
;
220 struct scsipi_periph
*periph
;
221 struct spifi_softc
*sc
= device_private(chan
->chan_adapter
->adapt_dev
);
222 struct spifi_scb
*scb
;
227 case ADAPTER_REQ_RUN_XFER
:
229 periph
= xs
->xs_periph
;
231 DPRINTF("spifi_scsi_cmd\n");
233 flags
= xs
->xs_control
;
235 scb
= spifi_get_scb(sc
);
237 panic("spifi_scsipi_request: no scb");
243 scb
->daddr
= (vaddr_t
)xs
->data
;
244 scb
->resid
= xs
->datalen
;
245 memcpy(&scb
->cmd
, xs
->cmd
, xs
->cmdlen
);
246 scb
->cmdlen
= xs
->cmdlen
;
248 scb
->target
= periph
->periph_target
;
249 scb
->lun
= periph
->periph_lun
;
250 scb
->lun_targ
= scb
->target
| (scb
->lun
<< 3);
252 if (flags
& XS_CTL_DATA_IN
)
253 scb
->flags
|= SPIFI_READ
;
257 TAILQ_INSERT_TAIL(&sc
->ready_scb
, scb
, chain
);
259 if (sc
->sc_nexus
== NULL
) /* IDLE */
264 if (flags
& XS_CTL_POLL
) {
265 if (spifi_poll(sc
)) {
266 printf("spifi: timeout\n");
268 printf("spifi: timeout again\n");
272 case ADAPTER_REQ_GROW_RESOURCES
:
273 /* XXX Not supported. */
275 case ADAPTER_REQ_SET_XFER_MODE
:
276 /* XXX Not supported. */
282 spifi_get_scb(struct spifi_softc
*sc
)
284 struct spifi_scb
*scb
;
288 scb
= TAILQ_FIRST(&sc
->free_scb
);
290 TAILQ_REMOVE(&sc
->free_scb
, scb
, chain
);
297 spifi_free_scb(struct spifi_softc
*sc
, struct spifi_scb
*scb
)
302 TAILQ_INSERT_HEAD(&sc
->free_scb
, scb
, chain
);
307 spifi_poll(struct spifi_softc
*sc
)
309 struct spifi_scb
*scb
= sc
->sc_nexus
;
310 struct scsipi_xfer
*xs
;
313 printf("%s: not implemented yet\n", __func__
);
315 scb
->status
= SCSI_OK
;
327 if (dmac3_intr(sc
->sc_dma
) != 0)
330 if (xs
->xs_status
& XS_STS_DONE
)
339 spifi_minphys(struct buf
*bp
)
342 if (bp
->b_bcount
> 64 * 1024)
343 bp
->b_bcount
= 64 * 1024;
349 spifi_sched(struct spifi_softc
*sc
)
351 struct spifi_scb
*scb
;
353 scb
= TAILQ_FIRST(&sc
->ready_scb
);
355 if (scb
== NULL
|| sc
->sc_nexus
!= NULL
)
358 if (sc
->sc_targets
[scb
->target
] & (1 << scb
->lun
))
361 TAILQ_REMOVE(&sc
->ready_scb
, scb
, chain
);
367 printf("spifi_sched: ID:LUN = %d:%d, ", scb
->target
, scb
->lun
);
368 printf("cmd = 0x%x", scb
->cmd
.opcode
);
369 for (i
= 0; i
< 5; i
++)
370 printf(" 0x%x", scb
->cmd
.bytes
[i
]);
375 DMAC3_SLOWACCESS(sc
);
378 DMAC3_FASTACCESS(sc
);
380 scb
= scb
->chain
.tqe_next
;
385 spifi_read_count(struct spifi_reg
*reg
)
389 count
= (reg
->count_hi
& 0xff) << 16 |
390 (reg
->count_mid
& 0xff) << 8 |
391 (reg
->count_low
& 0xff);
396 spifi_write_count(struct spifi_reg
*reg
, int count
)
399 reg
->count_hi
= count
>> 16;
400 reg
->count_mid
= count
>> 8;
401 reg
->count_low
= count
;
406 static const char scsi_phase_name
[][8] = {
407 "DATAOUT", "DATAIN", "COMMAND", "STATUS",
408 "", "", "MSGOUT", "MSGIN"
415 struct spifi_softc
*sc
= v
;
416 struct spifi_reg
*reg
= sc
->sc_reg
;
417 int intr
, state
, icond
;
418 struct spifi_scb
*scb
;
419 struct scsipi_xfer
*xs
;
424 switch (dmac3_intr(sc
->sc_dma
)) {
426 DPRINTF("spurious DMA intr\n");
429 printf("DMAC parity error, data PAD\n");
431 DMAC3_SLOWACCESS(sc
);
432 reg
->prcmd
= PRC_TRPAD
;
433 DMAC3_FASTACCESS(sc
);
439 DMAC3_SLOWACCESS(sc
);
441 intr
= reg
->intr
& 0xff;
443 DMAC3_FASTACCESS(sc
);
444 DPRINTF("spurious intr (not me)\n");
453 /* clear interrupt */
457 snprintb(bitmask
, sizeof bitmask
, INTR_BITMASK
, intr
);
458 printf("spifi_intr intr = 0x%s (%s), ", bitmask
,
459 scsi_phase_name
[(reg
->prstat
>> 3) & 7]);
460 printf("state = 0x%x, icond = 0x%x\n", state
, icond
);
463 if (intr
& INTR_FCOMP
) {
464 spifi_fifo_drain(sc
);
465 scb
->status
= reg
->cmbuf
[scb
->target
].status
;
466 scb
->resid
= spifi_read_count(reg
);
468 DPRINTF("datalen = %d, resid = %d, status = 0x%x\n",
469 xs
->datalen
, scb
->resid
, scb
->status
);
470 DPRINTF("msg = 0x%x\n", reg
->cmbuf
[sc
->sc_id
].cdb
[0]);
472 DMAC3_FASTACCESS(sc
);
476 if (intr
& INTR_DISCON
)
477 panic("%s: disconnect", __func__
);
479 if (intr
& INTR_TIMEO
) {
480 xs
->error
= XS_SELTIMEOUT
;
481 DMAC3_FASTACCESS(sc
);
485 if (intr
& INTR_BSRQ
) {
487 panic("%s: reconnect?", __func__
);
489 if (intr
& INTR_PERR
) {
490 printf("%s: %d:%d parity error\n",
491 device_xname(sc
->sc_dev
),
492 scb
->target
, scb
->lun
);
495 xs
->error
= XS_DRIVER_STUFFUP
;
500 if (state
>> 4 == SPS_MSGIN
&& icond
== ICOND_NXTREQ
)
501 panic("%s: NXTREQ", __func__
);
502 if (reg
->fifoctrl
& FIFOC_RQOVRN
)
503 panic("%s: RQOVRN", __func__
);
504 if (icond
== ICOND_UXPHASEZ
)
505 panic("ICOND_UXPHASEZ");
507 if ((icond
& 0x0f) == ICOND_ADATAOFF
) {
511 if ((icond
& 0xf0) == ICOND_UBF
) {
512 reg
->exstat
= reg
->exstat
& ~EXS_UBF
;
518 * XXX Work around the SPIFI bug that interrupts during
521 if (state
== ((SPS_DATAOUT
<< 4) | SPS_INTR
) &&
522 (reg
->prstat
& PRS_PHASE
) == SPIFI_DATAOUT
) {
523 reg
->prcmd
= PRC_DATAOUT
;
526 if ((reg
->prstat
& PRS_Z
) == 0) {
531 panic("%s: unknown intr state", __func__
);
535 DMAC3_FASTACCESS(sc
);
540 spifi_pmatch(struct spifi_softc
*sc
)
542 struct spifi_reg
*reg
= sc
->sc_reg
;
545 phase
= (reg
->prstat
& PRS_PHASE
);
548 printf("%s (%s)\n", __func__
, scsi_phase_name
[phase
>> 3]);
564 case SPIFI_MSGIN
: /* XXX */
565 case SPIFI_MSGOUT
: /* XXX */
567 printf("spifi: unknown phase %d\n", phase
);
572 spifi_select(struct spifi_softc
*sc
)
574 struct spifi_reg
*reg
= sc
->sc_reg
;
575 struct spifi_scb
*scb
= sc
->sc_nexus
;
579 if (reg
->loopdata
|| reg
->intr
)
584 printf("%s: spifi_select: NULL nexus\n",
585 device_xname(sc
->sc_dev
));
589 reg
->exctrl
= EXC_IPLOCK
;
591 dmac3_reset(sc
->sc_dma
);
592 sel
= scb
->target
<< 4 | SEL_ISTART
| SEL_IRESELEN
| SEL_WATN
;
593 spifi_sendmsg(sc
, SEND_IDENTIFY
);
598 spifi_sendmsg(struct spifi_softc
*sc
, int msg
)
600 struct spifi_scb
*scb
= sc
->sc_nexus
;
601 /* struct mesh_tinfo *ti; */
605 struct spifi_reg
*reg
= sc
->sc_reg
;
607 DPRINTF("%s: sending", __func__
);
611 if (msg
& SEND_REJECT
) {
613 sc
->sc_omsg
[len
++] = MSG_MESSAGE_REJECT
;
615 if (msg
& SEND_IDENTIFY
) {
616 DPRINTF(" IDENTIFY");
617 lun
= scb
->xs
->xs_periph
->periph_lun
;
618 sc
->sc_omsg
[len
++] = MSG_IDENTIFY(lun
, 0);
620 if (msg
& SEND_SDTR
) {
623 ti
= &sc
->sc_tinfo
[scb
->target
];
624 sc
->sc_omsg
[len
++] = MSG_EXTENDED
;
625 sc
->sc_omsg
[len
++] = 3;
626 sc
->sc_omsg
[len
++] = MSG_EXT_SDTR
;
627 sc
->sc_omsg
[len
++] = ti
->period
;
628 sc
->sc_omsg
[len
++] = ti
->offset
;
633 reg
->cmlen
= CML_AMSG_EN
| len
;
634 for (i
= 0; i
< len
; i
++)
635 reg
->cmbuf
[id
].cdb
[i
] = sc
->sc_omsg
[i
];
639 spifi_command(struct spifi_softc
*sc
)
641 struct spifi_scb
*scb
= sc
->sc_nexus
;
642 struct spifi_reg
*reg
= sc
->sc_reg
;
643 int len
= scb
->cmdlen
;
644 uint8_t *cmdp
= (uint8_t *)&scb
->cmd
;
647 DPRINTF("%s\n", __func__
);
649 reg
->cmdpage
= scb
->lun_targ
;
651 if (reg
->init_status
& IST_ACK
) {
653 reg
->prcmd
= PRC_NJMP
| PRC_CLRACK
| PRC_COMMAND
;
654 reg
->prcmd
= PRC_NJMP
| PRC_COMMAND
;
657 reg
->cmlen
= CML_AMSG_EN
| len
;
659 for (i
= 0; i
< len
; i
++)
660 reg
->cmbuf
[sc
->sc_id
].cdb
[i
] = *cmdp
++;
662 reg
->prcmd
= PRC_COMMAND
;
666 spifi_data_io(struct spifi_softc
*sc
)
668 struct spifi_scb
*scb
= sc
->sc_nexus
;
669 struct spifi_reg
*reg
= sc
->sc_reg
;
672 DPRINTF("%s\n", __func__
);
674 phase
= reg
->prstat
& PRS_PHASE
;
675 dmac3_reset(sc
->sc_dma
);
677 spifi_write_count(reg
, scb
->resid
);
678 reg
->cmlen
= CML_AMSG_EN
| 1;
681 scb
->flags
|= SPIFI_DMA
;
682 if (phase
== SPIFI_DATAIN
) {
683 if (reg
->fifoctrl
& FIFOC_SSTKACT
) {
685 * Clear FIFO and load the contents of synchronous
686 * stack into the FIFO.
688 reg
->fifoctrl
= FIFOC_CLREVEN
;
689 reg
->fifoctrl
= FIFOC_LOAD
;
691 reg
->autodata
= ADATA_IN
| scb
->lun_targ
;
692 dmac3_start(sc
->sc_dma
, scb
->daddr
, scb
->resid
, DMAC3_CSR_RECV
);
693 reg
->prcmd
= PRC_DATAIN
;
695 reg
->fifoctrl
= FIFOC_CLREVEN
;
696 reg
->autodata
= scb
->lun_targ
;
697 dmac3_start(sc
->sc_dma
, scb
->daddr
, scb
->resid
, DMAC3_CSR_SEND
);
698 reg
->prcmd
= PRC_DATAOUT
;
703 spifi_status(struct spifi_softc
*sc
)
705 struct spifi_reg
*reg
= sc
->sc_reg
;
707 DPRINTF("%s\n", __func__
);
708 spifi_fifo_drain(sc
);
709 reg
->cmlen
= CML_AMSG_EN
| 1;
710 reg
->prcmd
= PRC_STATUS
;
714 spifi_done(struct spifi_softc
*sc
)
716 struct spifi_scb
*scb
= sc
->sc_nexus
;
717 struct scsipi_xfer
*xs
= scb
->xs
;
719 DPRINTF("%s\n", __func__
);
721 xs
->status
= scb
->status
;
722 if (xs
->status
== SCSI_CHECK
) {
723 DPRINTF("%s: CHECK CONDITION\n", __func__
);
724 if (xs
->error
== XS_NOERROR
)
728 xs
->resid
= scb
->resid
;
731 spifi_free_scb(sc
, scb
);
740 spifi_fifo_drain(struct spifi_softc
*sc
)
742 struct spifi_scb
*scb
= sc
->sc_nexus
;
743 struct spifi_reg
*reg
= sc
->sc_reg
;
744 int fifoctrl
, fifo_count
;
746 DPRINTF("%s\n", __func__
);
748 if ((scb
->flags
& SPIFI_READ
) == 0)
751 fifoctrl
= reg
->fifoctrl
;
752 if (fifoctrl
& FIFOC_SSTKACT
)
755 fifo_count
= 8 - (fifoctrl
& FIFOC_FSLOT
);
756 if (fifo_count
> 0 && (scb
->flags
& SPIFI_DMA
)) {
757 /* Flush data still in FIFO. */
758 reg
->fifoctrl
= FIFOC_FLUSH
;
762 reg
->fifoctrl
= FIFOC_CLREVEN
;
766 spifi_reset(struct spifi_softc
*sc
)
768 struct spifi_reg
*reg
= sc
->sc_reg
;
771 DPRINTF("%s\n", __func__
);
773 reg
->auxctrl
= AUXCTRL_SRST
;
774 reg
->auxctrl
= AUXCTRL_CRST
;
776 dmac3_reset(sc
->sc_dma
);
778 reg
->auxctrl
= AUXCTRL_SRST
;
779 reg
->auxctrl
= AUXCTRL_CRST
;
780 reg
->auxctrl
= AUXCTRL_DMAEDGE
;
782 /* Mask (only) target mode interrupts. */
783 reg
->imask
= INTR_TGSEL
| INTR_COMRECV
;
785 reg
->config
= CONFIG_DMABURST
| CONFIG_PCHKEN
| CONFIG_PGENEN
| id
;
786 reg
->fastwide
= FAST_FASTEN
;
790 /* Enable automatic status input except the initiator. */
791 reg
->autostat
= ~(1 << id
);
793 reg
->fifoctrl
= FIFOC_CLREVEN
;
794 spifi_write_count(reg
, 0);
796 /* Flush write buffer. */
801 spifi_bus_reset(struct spifi_softc
*sc
)
803 struct spifi_reg
*reg
= sc
->sc_reg
;
805 printf("%s: bus reset\n", device_xname(sc
->sc_dev
));
809 reg
->auxctrl
= AUXCTRL_SETRST
;
815 static uint8_t spifi_sync_period
[] = {
816 /* 0 1 2 3 4 5 6 7 8 9 10 11 */
817 137, 125, 112, 100, 87, 75, 62, 50, 43, 37, 31, 25
821 spifi_setsync(struct spifi_softc
*sc
, struct spifi_tinfo
*ti
)
824 if ((ti
->flags
& T_SYNCMODE
) == 0)
827 uint8_t period
= ti
->period
;
828 uint8_t offset
= ti
->offset
;
831 for (v
= sizeof(spifi_sync_period
) - 1; v
>= 0; v
--)
832 if (spifi_sync_period
[v
] >= period
)
835 reg
->data_xfer
= 0; /* XXX */
837 reg
->data_xfer
= v
<< 4 | offset
;