Skip to content

Commit 09ba0de

Browse files
vdsaogregkh
authored andcommitted
USB: fsl_udc_core: prepare for SoCs with BE registers and descriptors
On some SoCs, the USB controller registers and descriptors can be big or little endian, depending on the version of the chip. In order to be able to run the same kernel binary on different versions of an SoC, the BE/LE decision must be made at run time. Provide appropriate register and descriptor accessors which are configurable at run time using the configuration flags from fsl_usb2_platform_data data structure. This is in preparation for adding support for MPC5121E DR USB2 Controller to the FSL UDC driver. Signed-off-by: Anatolij Gustschin <[email protected]> Cc: Li Yang <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b703e47 commit 09ba0de

File tree

2 files changed

+100
-25
lines changed

2 files changed

+100
-25
lines changed

drivers/usb/gadget/fsl_udc_core.c

Lines changed: 98 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,64 @@ fsl_ep0_desc = {
7777
static void fsl_ep_fifo_flush(struct usb_ep *_ep);
7878

7979
#ifdef CONFIG_PPC32
80-
#define fsl_readl(addr) in_le32(addr)
81-
#define fsl_writel(val32, addr) out_le32(addr, val32)
82-
#else
80+
/*
81+
* On some SoCs, the USB controller registers can be big or little endian,
82+
* depending on the version of the chip. In order to be able to run the
83+
* same kernel binary on 2 different versions of an SoC, the BE/LE decision
84+
* must be made at run time. _fsl_readl and fsl_writel are pointers to the
85+
* BE or LE readl() and writel() functions, and fsl_readl() and fsl_writel()
86+
* call through those pointers. Platform code for SoCs that have BE USB
87+
* registers should set pdata->big_endian_mmio flag.
88+
*
89+
* This also applies to controller-to-cpu accessors for the USB descriptors,
90+
* since their endianness is also SoC dependant. Platform code for SoCs that
91+
* have BE USB descriptors should set pdata->big_endian_desc flag.
92+
*/
93+
static u32 _fsl_readl_be(const unsigned __iomem *p)
94+
{
95+
return in_be32(p);
96+
}
97+
98+
static u32 _fsl_readl_le(const unsigned __iomem *p)
99+
{
100+
return in_le32(p);
101+
}
102+
103+
static void _fsl_writel_be(u32 v, unsigned __iomem *p)
104+
{
105+
out_be32(p, v);
106+
}
107+
108+
static void _fsl_writel_le(u32 v, unsigned __iomem *p)
109+
{
110+
out_le32(p, v);
111+
}
112+
113+
static u32 (*_fsl_readl)(const unsigned __iomem *p);
114+
static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
115+
116+
#define fsl_readl(p) (*_fsl_readl)((p))
117+
#define fsl_writel(v, p) (*_fsl_writel)((v), (p))
118+
119+
static inline u32 cpu_to_hc32(const u32 x)
120+
{
121+
return udc_controller->pdata->big_endian_desc
122+
? (__force u32)cpu_to_be32(x)
123+
: (__force u32)cpu_to_le32(x);
124+
}
125+
126+
static inline u32 hc32_to_cpu(const u32 x)
127+
{
128+
return udc_controller->pdata->big_endian_desc
129+
? be32_to_cpu((__force __be32)x)
130+
: le32_to_cpu((__force __le32)x);
131+
}
132+
#else /* !CONFIG_PPC32 */
83133
#define fsl_readl(addr) readl(addr)
84134
#define fsl_writel(val32, addr) writel(val32, addr)
85-
#endif
135+
#define cpu_to_hc32(x) cpu_to_le32(x)
136+
#define hc32_to_cpu(x) le32_to_cpu(x)
137+
#endif /* CONFIG_PPC32 */
86138

87139
/********************************************************************
88140
* Internal Used Function
@@ -409,7 +461,7 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
409461
if (zlt)
410462
tmp |= EP_QUEUE_HEAD_ZLT_SEL;
411463

412-
p_QH->max_pkt_length = cpu_to_le32(tmp);
464+
p_QH->max_pkt_length = cpu_to_hc32(tmp);
413465
p_QH->next_dtd_ptr = 1;
414466
p_QH->size_ioc_int_sts = 0;
415467
}
@@ -616,7 +668,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
616668
struct fsl_req *lastreq;
617669
lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
618670
lastreq->tail->next_td_ptr =
619-
cpu_to_le32(req->head->td_dma & DTD_ADDR_MASK);
671+
cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
620672
/* Read prime bit, if 1 goto done */
621673
if (fsl_readl(&dr_regs->endpointprime) & bitmask)
622674
goto out;
@@ -641,10 +693,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
641693

642694
/* Write dQH next pointer and terminate bit to 0 */
643695
temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
644-
dQH->next_dtd_ptr = cpu_to_le32(temp);
696+
dQH->next_dtd_ptr = cpu_to_hc32(temp);
645697

646698
/* Clear active and halt bit */
647-
temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
699+
temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
648700
| EP_QUEUE_HEAD_STATUS_HALT));
649701
dQH->size_ioc_int_sts &= temp;
650702

@@ -682,17 +734,17 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
682734

683735
dtd->td_dma = *dma;
684736
/* Clear reserved field */
685-
swap_temp = cpu_to_le32(dtd->size_ioc_sts);
737+
swap_temp = hc32_to_cpu(dtd->size_ioc_sts);
686738
swap_temp &= ~DTD_RESERVED_FIELDS;
687-
dtd->size_ioc_sts = cpu_to_le32(swap_temp);
739+
dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
688740

689741
/* Init all of buffer page pointers */
690742
swap_temp = (u32) (req->req.dma + req->req.actual);
691-
dtd->buff_ptr0 = cpu_to_le32(swap_temp);
692-
dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
693-
dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
694-
dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
695-
dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
743+
dtd->buff_ptr0 = cpu_to_hc32(swap_temp);
744+
dtd->buff_ptr1 = cpu_to_hc32(swap_temp + 0x1000);
745+
dtd->buff_ptr2 = cpu_to_hc32(swap_temp + 0x2000);
746+
dtd->buff_ptr3 = cpu_to_hc32(swap_temp + 0x3000);
747+
dtd->buff_ptr4 = cpu_to_hc32(swap_temp + 0x4000);
696748

697749
req->req.actual += *length;
698750

@@ -716,7 +768,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
716768
if (*is_last && !req->req.no_interrupt)
717769
swap_temp |= DTD_IOC;
718770

719-
dtd->size_ioc_sts = cpu_to_le32(swap_temp);
771+
dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
720772

721773
mb();
722774

@@ -743,15 +795,15 @@ static int fsl_req_to_dtd(struct fsl_req *req)
743795
is_first = 0;
744796
req->head = dtd;
745797
} else {
746-
last_dtd->next_td_ptr = cpu_to_le32(dma);
798+
last_dtd->next_td_ptr = cpu_to_hc32(dma);
747799
last_dtd->next_td_virt = dtd;
748800
}
749801
last_dtd = dtd;
750802

751803
req->dtd_count++;
752804
} while (!is_last);
753805

754-
dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
806+
dtd->next_td_ptr = cpu_to_hc32(DTD_NEXT_TERMINATE);
755807

756808
req->tail = dtd;
757809

@@ -1394,6 +1446,7 @@ static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr)
13941446
{
13951447
u32 temp;
13961448
struct ep_queue_head *qh;
1449+
struct fsl_usb2_platform_data *pdata = udc->pdata;
13971450

13981451
qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT];
13991452

@@ -1408,7 +1461,16 @@ static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr)
14081461
fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd);
14091462

14101463
/* Copy the setup packet to local buffer */
1411-
memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
1464+
if (pdata->le_setup_buf) {
1465+
u32 *p = (u32 *)buffer_ptr;
1466+
u32 *s = (u32 *)qh->setup_buffer;
1467+
1468+
/* Convert little endian setup buffer to CPU endian */
1469+
*p++ = le32_to_cpu(*s++);
1470+
*p = le32_to_cpu(*s);
1471+
} else {
1472+
memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
1473+
}
14121474
} while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW));
14131475

14141476
/* Clear Setup Tripwire */
@@ -1432,19 +1494,19 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
14321494
actual = curr_req->req.length;
14331495

14341496
for (j = 0; j < curr_req->dtd_count; j++) {
1435-
remaining_length = (le32_to_cpu(curr_td->size_ioc_sts)
1497+
remaining_length = (hc32_to_cpu(curr_td->size_ioc_sts)
14361498
& DTD_PACKET_SIZE)
14371499
>> DTD_LENGTH_BIT_POS;
14381500
actual -= remaining_length;
14391501

1440-
if ((errors = le32_to_cpu(curr_td->size_ioc_sts) &
1441-
DTD_ERROR_MASK)) {
1502+
errors = hc32_to_cpu(curr_td->size_ioc_sts);
1503+
if (errors & DTD_ERROR_MASK) {
14421504
if (errors & DTD_STATUS_HALTED) {
14431505
ERR("dTD error %08x QH=%d\n", errors, pipe);
14441506
/* Clear the errors and Halt condition */
1445-
tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);
1507+
tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts);
14461508
tmp &= ~errors;
1447-
curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);
1509+
curr_qh->size_ioc_int_sts = cpu_to_hc32(tmp);
14481510
status = -EPIPE;
14491511
/* FIXME: continue with next queued TD? */
14501512

@@ -1462,7 +1524,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
14621524
ERR("Unknown error has occurred (0x%x)!\n",
14631525
errors);
14641526

1465-
} else if (le32_to_cpu(curr_td->size_ioc_sts)
1527+
} else if (hc32_to_cpu(curr_td->size_ioc_sts)
14661528
& DTD_STATUS_ACTIVE) {
14671529
VDBG("Request not complete");
14681530
status = REQ_UNCOMPLETE;
@@ -2233,6 +2295,7 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
22332295
*/
22342296
static int __init fsl_udc_probe(struct platform_device *pdev)
22352297
{
2298+
struct fsl_usb2_platform_data *pdata;
22362299
struct resource *res;
22372300
int ret = -ENODEV;
22382301
unsigned int i;
@@ -2249,6 +2312,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
22492312
return -ENOMEM;
22502313
}
22512314

2315+
pdata = pdev->dev.platform_data;
2316+
udc_controller->pdata = pdata;
22522317
spin_lock_init(&udc_controller->lock);
22532318
udc_controller->stopped = 1;
22542319

@@ -2271,6 +2336,14 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
22712336
goto err_release_mem_region;
22722337
}
22732338

2339+
if (pdata->big_endian_mmio) {
2340+
_fsl_readl = _fsl_readl_be;
2341+
_fsl_writel = _fsl_writel_be;
2342+
} else {
2343+
_fsl_readl = _fsl_readl_le;
2344+
_fsl_writel = _fsl_writel_le;
2345+
}
2346+
22742347
#ifndef CONFIG_ARCH_MXC
22752348
usb_sys_regs = (struct usb_sys_interface *)
22762349
((u32)dr_regs + USB_DR_SYS_OFFSET);

drivers/usb/gadget/fsl_usb2_udc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ struct fsl_ep {
461461
struct fsl_udc {
462462
struct usb_gadget gadget;
463463
struct usb_gadget_driver *driver;
464+
struct fsl_usb2_platform_data *pdata;
464465
struct completion *done; /* to make sure release() is done */
465466
struct fsl_ep *eps;
466467
unsigned int max_ep;
@@ -473,6 +474,7 @@ struct fsl_udc {
473474
unsigned vbus_active:1;
474475
unsigned stopped:1;
475476
unsigned remote_wakeup:1;
477+
unsigned big_endian_desc:1;
476478

477479
struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
478480
struct fsl_req *status_req; /* ep0 status request */

0 commit comments

Comments
 (0)