18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Renesas USB driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Renesas Solutions Corp. 68c2ecf20Sopenharmony_ci * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include "common.h" 118c2ecf20Sopenharmony_ci#include "pipe.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* 148c2ecf20Sopenharmony_ci * macros 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci#define usbhsp_addr_offset(p) ((usbhs_pipe_number(p) - 1) * 2) 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define usbhsp_flags_set(p, f) ((p)->flags |= USBHS_PIPE_FLAGS_##f) 198c2ecf20Sopenharmony_ci#define usbhsp_flags_clr(p, f) ((p)->flags &= ~USBHS_PIPE_FLAGS_##f) 208c2ecf20Sopenharmony_ci#define usbhsp_flags_has(p, f) ((p)->flags & USBHS_PIPE_FLAGS_##f) 218c2ecf20Sopenharmony_ci#define usbhsp_flags_init(p) do {(p)->flags = 0; } while (0) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * for debug 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_cistatic char *usbhsp_pipe_name[] = { 278c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = "DCP", 288c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = "BULK", 298c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = "INT", 308c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = "ISO", 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cichar *usbhs_pipe_name(struct usbhs_pipe *pipe) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci return usbhsp_pipe_name[usbhs_pipe_type(pipe)]; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic struct renesas_usbhs_driver_pipe_config 398c2ecf20Sopenharmony_ci*usbhsp_get_pipe_config(struct usbhs_priv *priv, int pipe_num) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct renesas_usbhs_driver_pipe_config *pipe_configs = 428c2ecf20Sopenharmony_ci usbhs_get_dparam(priv, pipe_configs); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci return &pipe_configs[pipe_num]; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * DCPCTR/PIPEnCTR functions 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_cistatic void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 538c2ecf20Sopenharmony_ci int offset = usbhsp_addr_offset(pipe); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 568c2ecf20Sopenharmony_ci usbhs_bset(priv, DCPCTR, mask, val); 578c2ecf20Sopenharmony_ci else 588c2ecf20Sopenharmony_ci usbhs_bset(priv, PIPEnCTR + offset, mask, val); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 648c2ecf20Sopenharmony_ci int offset = usbhsp_addr_offset(pipe); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 678c2ecf20Sopenharmony_ci return usbhs_read(priv, DCPCTR); 688c2ecf20Sopenharmony_ci else 698c2ecf20Sopenharmony_ci return usbhs_read(priv, PIPEnCTR + offset); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * DCP/PIPE functions 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistatic void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe, 768c2ecf20Sopenharmony_ci u16 dcp_reg, u16 pipe_reg, 778c2ecf20Sopenharmony_ci u16 mask, u16 val) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 828c2ecf20Sopenharmony_ci usbhs_bset(priv, dcp_reg, mask, val); 838c2ecf20Sopenharmony_ci else 848c2ecf20Sopenharmony_ci usbhs_bset(priv, pipe_reg, mask, val); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic u16 __usbhsp_pipe_xxx_get(struct usbhs_pipe *pipe, 888c2ecf20Sopenharmony_ci u16 dcp_reg, u16 pipe_reg) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 938c2ecf20Sopenharmony_ci return usbhs_read(priv, dcp_reg); 948c2ecf20Sopenharmony_ci else 958c2ecf20Sopenharmony_ci return usbhs_read(priv, pipe_reg); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* 998c2ecf20Sopenharmony_ci * DCPCFG/PIPECFG functions 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_cistatic void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, DCPCFG, PIPECFG, mask, val); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic u16 usbhsp_pipe_cfg_get(struct usbhs_pipe *pipe) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci return __usbhsp_pipe_xxx_get(pipe, DCPCFG, PIPECFG); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci * PIPEnTRN/PIPEnTRE functions 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_cistatic void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 1178c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 1188c2ecf20Sopenharmony_ci int num = usbhs_pipe_number(pipe); 1198c2ecf20Sopenharmony_ci u16 reg; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* 1228c2ecf20Sopenharmony_ci * It is impossible to calculate address, 1238c2ecf20Sopenharmony_ci * since PIPEnTRN addresses were mapped randomly. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci#define CASE_PIPExTRN(a) \ 1268c2ecf20Sopenharmony_ci case 0x ## a: \ 1278c2ecf20Sopenharmony_ci reg = PIPE ## a ## TRN; \ 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci switch (num) { 1318c2ecf20Sopenharmony_ci CASE_PIPExTRN(1); 1328c2ecf20Sopenharmony_ci CASE_PIPExTRN(2); 1338c2ecf20Sopenharmony_ci CASE_PIPExTRN(3); 1348c2ecf20Sopenharmony_ci CASE_PIPExTRN(4); 1358c2ecf20Sopenharmony_ci CASE_PIPExTRN(5); 1368c2ecf20Sopenharmony_ci CASE_PIPExTRN(B); 1378c2ecf20Sopenharmony_ci CASE_PIPExTRN(C); 1388c2ecf20Sopenharmony_ci CASE_PIPExTRN(D); 1398c2ecf20Sopenharmony_ci CASE_PIPExTRN(E); 1408c2ecf20Sopenharmony_ci CASE_PIPExTRN(F); 1418c2ecf20Sopenharmony_ci CASE_PIPExTRN(9); 1428c2ecf20Sopenharmony_ci CASE_PIPExTRN(A); 1438c2ecf20Sopenharmony_ci default: 1448c2ecf20Sopenharmony_ci dev_err(dev, "unknown pipe (%d)\n", num); 1458c2ecf20Sopenharmony_ci return; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void usbhsp_pipe_tre_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 1538c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 1548c2ecf20Sopenharmony_ci int num = usbhs_pipe_number(pipe); 1558c2ecf20Sopenharmony_ci u16 reg; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* 1588c2ecf20Sopenharmony_ci * It is impossible to calculate address, 1598c2ecf20Sopenharmony_ci * since PIPEnTRE addresses were mapped randomly. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci#define CASE_PIPExTRE(a) \ 1628c2ecf20Sopenharmony_ci case 0x ## a: \ 1638c2ecf20Sopenharmony_ci reg = PIPE ## a ## TRE; \ 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci switch (num) { 1678c2ecf20Sopenharmony_ci CASE_PIPExTRE(1); 1688c2ecf20Sopenharmony_ci CASE_PIPExTRE(2); 1698c2ecf20Sopenharmony_ci CASE_PIPExTRE(3); 1708c2ecf20Sopenharmony_ci CASE_PIPExTRE(4); 1718c2ecf20Sopenharmony_ci CASE_PIPExTRE(5); 1728c2ecf20Sopenharmony_ci CASE_PIPExTRE(B); 1738c2ecf20Sopenharmony_ci CASE_PIPExTRE(C); 1748c2ecf20Sopenharmony_ci CASE_PIPExTRE(D); 1758c2ecf20Sopenharmony_ci CASE_PIPExTRE(E); 1768c2ecf20Sopenharmony_ci CASE_PIPExTRE(F); 1778c2ecf20Sopenharmony_ci CASE_PIPExTRE(9); 1788c2ecf20Sopenharmony_ci CASE_PIPExTRE(A); 1798c2ecf20Sopenharmony_ci default: 1808c2ecf20Sopenharmony_ci dev_err(dev, "unknown pipe (%d)\n", num); 1818c2ecf20Sopenharmony_ci return; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* 1888c2ecf20Sopenharmony_ci * PIPEBUF 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_cistatic void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 1938c2ecf20Sopenharmony_ci return; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, 0, PIPEBUF, mask, val); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* 1998c2ecf20Sopenharmony_ci * DCPMAXP/PIPEMAXP 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_cistatic void usbhsp_pipe_maxp_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, DCPMAXP, PIPEMAXP, mask, val); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/* 2078c2ecf20Sopenharmony_ci * pipe control functions 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistatic void usbhsp_pipe_select(struct usbhs_pipe *pipe) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* 2148c2ecf20Sopenharmony_ci * On pipe, this is necessary before 2158c2ecf20Sopenharmony_ci * accesses to below registers. 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * PIPESEL : usbhsp_pipe_select 2188c2ecf20Sopenharmony_ci * PIPECFG : usbhsp_pipe_cfg_xxx 2198c2ecf20Sopenharmony_ci * PIPEBUF : usbhsp_pipe_buf_xxx 2208c2ecf20Sopenharmony_ci * PIPEMAXP : usbhsp_pipe_maxp_xxx 2218c2ecf20Sopenharmony_ci * PIPEPERI 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* 2258c2ecf20Sopenharmony_ci * if pipe is dcp, no pipe is selected. 2268c2ecf20Sopenharmony_ci * it is no problem, because dcp have its register 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci usbhs_write(priv, PIPESEL, 0xF & usbhs_pipe_number(pipe)); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 2348c2ecf20Sopenharmony_ci int timeout = 1024; 2358c2ecf20Sopenharmony_ci u16 mask = usbhs_mod_is_host(priv) ? (CSSTS | PID_MASK) : PID_MASK; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * make sure.... 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is 2418c2ecf20Sopenharmony_ci * specified by the CURPIPE bits. 2428c2ecf20Sopenharmony_ci * When changing the setting of this bit after changing 2438c2ecf20Sopenharmony_ci * the PID bits for the selected pipe from BUF to NAK, 2448c2ecf20Sopenharmony_ci * check that CSSTS = 0 and PBUSY = 0. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * CURPIPE bit = 0 2498c2ecf20Sopenharmony_ci * 2508c2ecf20Sopenharmony_ci * see also 2518c2ecf20Sopenharmony_ci * "Operation" 2528c2ecf20Sopenharmony_ci * - "Pipe Control" 2538c2ecf20Sopenharmony_ci * - "Pipe Control Registers Switching Procedure" 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_ci usbhs_write(priv, CFIFOSEL, 0); 2568c2ecf20Sopenharmony_ci usbhs_pipe_disable(pipe); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci do { 2598c2ecf20Sopenharmony_ci if (!(usbhsp_pipectrl_get(pipe) & mask)) 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci udelay(10); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci } while (timeout--); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return -EBUSY; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ciint usbhs_pipe_is_accessible(struct usbhs_pipe *pipe) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci u16 val; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci val = usbhsp_pipectrl_get(pipe); 2748c2ecf20Sopenharmony_ci if (val & BSTS) 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return -EBUSY; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cibool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci u16 val; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Do not support for DCP pipe */ 2858c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 2868c2ecf20Sopenharmony_ci return false; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci val = usbhsp_pipectrl_get(pipe); 2898c2ecf20Sopenharmony_ci if (val & INBUFM) 2908c2ecf20Sopenharmony_ci return true; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return false; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* 2968c2ecf20Sopenharmony_ci * PID ctrl 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_cistatic void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci u16 pid = usbhsp_pipectrl_get(pipe); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci pid &= PID_MASK; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* 3058c2ecf20Sopenharmony_ci * see 3068c2ecf20Sopenharmony_ci * "Pipe n Control Register" - "PID" 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ci switch (pid) { 3098c2ecf20Sopenharmony_ci case PID_STALL11: 3108c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); 3118c2ecf20Sopenharmony_ci fallthrough; 3128c2ecf20Sopenharmony_ci case PID_STALL10: 3138c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_civoid usbhs_pipe_disable(struct usbhs_pipe *pipe) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci int timeout = 1024; 3208c2ecf20Sopenharmony_ci u16 val; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* see "Pipe n Control Register" - "PID" */ 3238c2ecf20Sopenharmony_ci __usbhsp_pid_try_nak_if_stall(pipe); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci do { 3288c2ecf20Sopenharmony_ci val = usbhsp_pipectrl_get(pipe); 3298c2ecf20Sopenharmony_ci val &= PBUSY; 3308c2ecf20Sopenharmony_ci if (!val) 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci udelay(10); 3348c2ecf20Sopenharmony_ci } while (timeout--); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_civoid usbhs_pipe_enable(struct usbhs_pipe *pipe) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci /* see "Pipe n Control Register" - "PID" */ 3408c2ecf20Sopenharmony_ci __usbhsp_pid_try_nak_if_stall(pipe); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_BUF); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_civoid usbhs_pipe_stall(struct usbhs_pipe *pipe) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci u16 pid = usbhsp_pipectrl_get(pipe); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci pid &= PID_MASK; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* 3528c2ecf20Sopenharmony_ci * see 3538c2ecf20Sopenharmony_ci * "Pipe n Control Register" - "PID" 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci switch (pid) { 3568c2ecf20Sopenharmony_ci case PID_NAK: 3578c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci case PID_BUF: 3608c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL11); 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ciint usbhs_pipe_is_stall(struct usbhs_pipe *pipe) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return (int)(pid == PID_STALL10 || pid == PID_STALL11); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_civoid usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) 3758c2ecf20Sopenharmony_ci return; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * clear and disable transfer counter for IN/OUT pipe 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ci usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * Only IN direction bulk pipe can use transfer count. 3848c2ecf20Sopenharmony_ci * Without using this function, 3858c2ecf20Sopenharmony_ci * received data will break if it was large data size. 3868c2ecf20Sopenharmony_ci * see PIPEnTRN/PIPEnTRE for detail 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dir_in(pipe)) { 3898c2ecf20Sopenharmony_ci int maxp = usbhs_pipe_get_maxpacket(pipe); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci usbhsp_pipe_trn_set(pipe, 0xffff, DIV_ROUND_UP(len, maxp)); 3928c2ecf20Sopenharmony_ci usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */ 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/* 3988c2ecf20Sopenharmony_ci * pipe setup 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_cistatic int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host, 4018c2ecf20Sopenharmony_ci int dir_in, u16 *pipecfg) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci u16 type = 0; 4048c2ecf20Sopenharmony_ci u16 bfre = 0; 4058c2ecf20Sopenharmony_ci u16 dblb = 0; 4068c2ecf20Sopenharmony_ci u16 cntmd = 0; 4078c2ecf20Sopenharmony_ci u16 dir = 0; 4088c2ecf20Sopenharmony_ci u16 epnum = 0; 4098c2ecf20Sopenharmony_ci u16 shtnak = 0; 4108c2ecf20Sopenharmony_ci static const u16 type_array[] = { 4118c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = TYPE_BULK, 4128c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = TYPE_INT, 4138c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = TYPE_ISO, 4148c2ecf20Sopenharmony_ci }; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 4178c2ecf20Sopenharmony_ci return -EINVAL; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* 4208c2ecf20Sopenharmony_ci * PIPECFG 4218c2ecf20Sopenharmony_ci * 4228c2ecf20Sopenharmony_ci * see 4238c2ecf20Sopenharmony_ci * - "Register Descriptions" - "PIPECFG" register 4248c2ecf20Sopenharmony_ci * - "Features" - "Pipe configuration" 4258c2ecf20Sopenharmony_ci * - "Operation" - "Pipe Control" 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* TYPE */ 4298c2ecf20Sopenharmony_ci type = type_array[usbhs_pipe_type(pipe)]; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* BFRE */ 4328c2ecf20Sopenharmony_ci if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) || 4338c2ecf20Sopenharmony_ci usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) 4348c2ecf20Sopenharmony_ci bfre = 0; /* FIXME */ 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* DBLB: see usbhs_pipe_config_update() */ 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* CNTMD */ 4398c2ecf20Sopenharmony_ci if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) 4408c2ecf20Sopenharmony_ci cntmd = 0; /* FIXME */ 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* DIR */ 4438c2ecf20Sopenharmony_ci if (dir_in) 4448c2ecf20Sopenharmony_ci usbhsp_flags_set(pipe, IS_DIR_HOST); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (!!is_host ^ !!dir_in) 4478c2ecf20Sopenharmony_ci dir |= DIR_OUT; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (!dir) 4508c2ecf20Sopenharmony_ci usbhsp_flags_set(pipe, IS_DIR_IN); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* SHTNAK */ 4538c2ecf20Sopenharmony_ci if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) && 4548c2ecf20Sopenharmony_ci !dir) 4558c2ecf20Sopenharmony_ci shtnak = SHTNAK; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* EPNUM */ 4588c2ecf20Sopenharmony_ci epnum = 0; /* see usbhs_pipe_config_update() */ 4598c2ecf20Sopenharmony_ci *pipecfg = type | 4608c2ecf20Sopenharmony_ci bfre | 4618c2ecf20Sopenharmony_ci dblb | 4628c2ecf20Sopenharmony_ci cntmd | 4638c2ecf20Sopenharmony_ci dir | 4648c2ecf20Sopenharmony_ci shtnak | 4658c2ecf20Sopenharmony_ci epnum; 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 4728c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 4738c2ecf20Sopenharmony_ci int pipe_num = usbhs_pipe_number(pipe); 4748c2ecf20Sopenharmony_ci u16 buff_size; 4758c2ecf20Sopenharmony_ci u16 bufnmb; 4768c2ecf20Sopenharmony_ci u16 bufnmb_cnt; 4778c2ecf20Sopenharmony_ci struct renesas_usbhs_driver_pipe_config *pipe_config = 4788c2ecf20Sopenharmony_ci usbhsp_get_pipe_config(priv, pipe_num); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* 4818c2ecf20Sopenharmony_ci * PIPEBUF 4828c2ecf20Sopenharmony_ci * 4838c2ecf20Sopenharmony_ci * see 4848c2ecf20Sopenharmony_ci * - "Register Descriptions" - "PIPEBUF" register 4858c2ecf20Sopenharmony_ci * - "Features" - "Pipe configuration" 4868c2ecf20Sopenharmony_ci * - "Operation" - "FIFO Buffer Memory" 4878c2ecf20Sopenharmony_ci * - "Operation" - "Pipe Control" 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_ci buff_size = pipe_config->bufsize; 4908c2ecf20Sopenharmony_ci bufnmb = pipe_config->bufnum; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* change buff_size to register value */ 4938c2ecf20Sopenharmony_ci bufnmb_cnt = (buff_size / 64) - 1; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci dev_dbg(dev, "pipe : %d : buff_size 0x%x: bufnmb 0x%x\n", 4968c2ecf20Sopenharmony_ci pipe_num, buff_size, bufnmb); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return (0x1f & bufnmb_cnt) << 10 | 4998c2ecf20Sopenharmony_ci (0xff & bufnmb) << 0; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_civoid usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, 5038c2ecf20Sopenharmony_ci u16 epnum, u16 maxp) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 5068c2ecf20Sopenharmony_ci int pipe_num = usbhs_pipe_number(pipe); 5078c2ecf20Sopenharmony_ci struct renesas_usbhs_driver_pipe_config *pipe_config = 5088c2ecf20Sopenharmony_ci usbhsp_get_pipe_config(priv, pipe_num); 5098c2ecf20Sopenharmony_ci u16 dblb = pipe_config->double_buf ? DBLB : 0; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (devsel > 0xA) { 5128c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci dev_err(dev, "devsel error %d\n", devsel); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci devsel = 0; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci usbhsp_pipe_barrier(pipe); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci pipe->maxp = maxp; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci usbhsp_pipe_select(pipe); 5248c2ecf20Sopenharmony_ci usbhsp_pipe_maxp_set(pipe, 0xFFFF, 5258c2ecf20Sopenharmony_ci (devsel << 12) | 5268c2ecf20Sopenharmony_ci maxp); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (!usbhs_pipe_is_dcp(pipe)) 5298c2ecf20Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, 0x000F | DBLB, epnum | dblb); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/* 5338c2ecf20Sopenharmony_ci * pipe control 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ciint usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci /* 5388c2ecf20Sopenharmony_ci * see 5398c2ecf20Sopenharmony_ci * usbhs_pipe_config_update() 5408c2ecf20Sopenharmony_ci * usbhs_dcp_malloc() 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci return pipe->maxp; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ciint usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci return usbhsp_flags_has(pipe, IS_DIR_IN); 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ciint usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci return usbhsp_flags_has(pipe, IS_DIR_HOST); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ciint usbhs_pipe_is_running(struct usbhs_pipe *pipe) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci return usbhsp_flags_has(pipe, IS_RUNNING); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_civoid usbhs_pipe_running(struct usbhs_pipe *pipe, int running) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci if (running) 5638c2ecf20Sopenharmony_ci usbhsp_flags_set(pipe, IS_RUNNING); 5648c2ecf20Sopenharmony_ci else 5658c2ecf20Sopenharmony_ci usbhsp_flags_clr(pipe, IS_RUNNING); 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_civoid usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci u16 mask = (SQCLR | SQSET); 5718c2ecf20Sopenharmony_ci u16 val; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* 5748c2ecf20Sopenharmony_ci * sequence 5758c2ecf20Sopenharmony_ci * 0 : data0 5768c2ecf20Sopenharmony_ci * 1 : data1 5778c2ecf20Sopenharmony_ci * -1 : no change 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci switch (sequence) { 5808c2ecf20Sopenharmony_ci case 0: 5818c2ecf20Sopenharmony_ci val = SQCLR; 5828c2ecf20Sopenharmony_ci break; 5838c2ecf20Sopenharmony_ci case 1: 5848c2ecf20Sopenharmony_ci val = SQSET; 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci default: 5878c2ecf20Sopenharmony_ci return; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, mask, val); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int usbhs_pipe_get_data_sequence(struct usbhs_pipe *pipe) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci return !!(usbhsp_pipectrl_get(pipe) & SQMON); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_civoid usbhs_pipe_clear(struct usbhs_pipe *pipe) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) { 6018c2ecf20Sopenharmony_ci usbhs_fifo_clear_dcp(pipe); 6028c2ecf20Sopenharmony_ci } else { 6038c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); 6048c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, ACLRM, 0); 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci/* Should call usbhsp_pipe_select() before */ 6098c2ecf20Sopenharmony_civoid usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe, 6108c2ecf20Sopenharmony_ci int needs_bfre, int bfre_enable) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci int sequence; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci usbhsp_pipe_select(pipe); 6158c2ecf20Sopenharmony_ci sequence = usbhs_pipe_get_data_sequence(pipe); 6168c2ecf20Sopenharmony_ci if (needs_bfre) 6178c2ecf20Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, BFRE, bfre_enable ? BFRE : 0); 6188c2ecf20Sopenharmony_ci usbhs_pipe_clear(pipe); 6198c2ecf20Sopenharmony_ci usbhs_pipe_data_sequence(pipe, sequence); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_civoid usbhs_pipe_config_change_bfre(struct usbhs_pipe *pipe, int enable) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 6258c2ecf20Sopenharmony_ci return; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci usbhsp_pipe_select(pipe); 6288c2ecf20Sopenharmony_ci /* check if the driver needs to change the BFRE value */ 6298c2ecf20Sopenharmony_ci if (!(enable ^ !!(usbhsp_pipe_cfg_get(pipe) & BFRE))) 6308c2ecf20Sopenharmony_ci return; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci usbhs_pipe_clear_without_sequence(pipe, 1, enable); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct usbhs_pipe *pos, *pipe; 6388c2ecf20Sopenharmony_ci int i; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* 6418c2ecf20Sopenharmony_ci * find target pipe 6428c2ecf20Sopenharmony_ci */ 6438c2ecf20Sopenharmony_ci pipe = NULL; 6448c2ecf20Sopenharmony_ci usbhs_for_each_pipe_with_dcp(pos, priv, i) { 6458c2ecf20Sopenharmony_ci if (!usbhs_pipe_type_is(pos, type)) 6468c2ecf20Sopenharmony_ci continue; 6478c2ecf20Sopenharmony_ci if (usbhsp_flags_has(pos, IS_USED)) 6488c2ecf20Sopenharmony_ci continue; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci pipe = pos; 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (!pipe) 6558c2ecf20Sopenharmony_ci return NULL; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* 6588c2ecf20Sopenharmony_ci * initialize pipe flags 6598c2ecf20Sopenharmony_ci */ 6608c2ecf20Sopenharmony_ci usbhsp_flags_init(pipe); 6618c2ecf20Sopenharmony_ci usbhsp_flags_set(pipe, IS_USED); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci return pipe; 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic void usbhsp_put_pipe(struct usbhs_pipe *pipe) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci usbhsp_flags_init(pipe); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_civoid usbhs_pipe_init(struct usbhs_priv *priv, 6728c2ecf20Sopenharmony_ci int (*dma_map_ctrl)(struct device *dma_dev, 6738c2ecf20Sopenharmony_ci struct usbhs_pkt *pkt, int map)) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); 6768c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe; 6778c2ecf20Sopenharmony_ci int i; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci usbhs_for_each_pipe_with_dcp(pipe, priv, i) { 6808c2ecf20Sopenharmony_ci usbhsp_flags_init(pipe); 6818c2ecf20Sopenharmony_ci pipe->fifo = NULL; 6828c2ecf20Sopenharmony_ci pipe->mod_private = NULL; 6838c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pipe->list); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* pipe force init */ 6868c2ecf20Sopenharmony_ci usbhs_pipe_clear(pipe); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci info->dma_map_ctrl = dma_map_ctrl; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistruct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, 6938c2ecf20Sopenharmony_ci int endpoint_type, 6948c2ecf20Sopenharmony_ci int dir_in) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 6978c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe; 6988c2ecf20Sopenharmony_ci int is_host = usbhs_mod_is_host(priv); 6998c2ecf20Sopenharmony_ci int ret; 7008c2ecf20Sopenharmony_ci u16 pipecfg, pipebuf; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci pipe = usbhsp_get_pipe(priv, endpoint_type); 7038c2ecf20Sopenharmony_ci if (!pipe) { 7048c2ecf20Sopenharmony_ci dev_err(dev, "can't get pipe (%s)\n", 7058c2ecf20Sopenharmony_ci usbhsp_pipe_name[endpoint_type]); 7068c2ecf20Sopenharmony_ci return NULL; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pipe->list); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci usbhs_pipe_disable(pipe); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* make sure pipe is not busy */ 7148c2ecf20Sopenharmony_ci ret = usbhsp_pipe_barrier(pipe); 7158c2ecf20Sopenharmony_ci if (ret < 0) { 7168c2ecf20Sopenharmony_ci dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe)); 7178c2ecf20Sopenharmony_ci return NULL; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) { 7218c2ecf20Sopenharmony_ci dev_err(dev, "can't setup pipe\n"); 7228c2ecf20Sopenharmony_ci return NULL; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci pipebuf = usbhsp_setup_pipebuff(pipe); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci usbhsp_pipe_select(pipe); 7288c2ecf20Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg); 7298c2ecf20Sopenharmony_ci usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf); 7308c2ecf20Sopenharmony_ci usbhs_pipe_clear(pipe); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci usbhs_pipe_sequence_data0(pipe); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci dev_dbg(dev, "enable pipe %d : %s (%s)\n", 7358c2ecf20Sopenharmony_ci usbhs_pipe_number(pipe), 7368c2ecf20Sopenharmony_ci usbhs_pipe_name(pipe), 7378c2ecf20Sopenharmony_ci usbhs_pipe_is_dir_in(pipe) ? "in" : "out"); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* 7408c2ecf20Sopenharmony_ci * epnum / maxp are still not set to this pipe. 7418c2ecf20Sopenharmony_ci * call usbhs_pipe_config_update() after this function !! 7428c2ecf20Sopenharmony_ci */ 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return pipe; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_civoid usbhs_pipe_free(struct usbhs_pipe *pipe) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci usbhsp_pipe_select(pipe); 7508c2ecf20Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, 0xFFFF, 0); 7518c2ecf20Sopenharmony_ci usbhsp_put_pipe(pipe); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_civoid usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci if (pipe->fifo) 7578c2ecf20Sopenharmony_ci pipe->fifo->pipe = NULL; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci pipe->fifo = fifo; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (fifo) 7628c2ecf20Sopenharmony_ci fifo->pipe = pipe; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci/* 7678c2ecf20Sopenharmony_ci * dcp control 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_cistruct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci pipe = usbhsp_get_pipe(priv, USB_ENDPOINT_XFER_CONTROL); 7748c2ecf20Sopenharmony_ci if (!pipe) 7758c2ecf20Sopenharmony_ci return NULL; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pipe->list); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* 7808c2ecf20Sopenharmony_ci * call usbhs_pipe_config_update() after this function !! 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci return pipe; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_civoid usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci WARN_ON(!usbhs_pipe_is_dcp(pipe)); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci usbhs_pipe_enable(pipe); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (!usbhs_mod_is_host(priv)) /* funconly */ 7958c2ecf20Sopenharmony_ci usbhsp_pipectrl_set(pipe, CCPL, CCPL); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_civoid usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, DIR_OUT, 8018c2ecf20Sopenharmony_ci dir_out ? DIR_OUT : 0); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci/* 8058c2ecf20Sopenharmony_ci * pipe module function 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_ciint usbhs_pipe_probe(struct usbhs_priv *priv) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); 8108c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe; 8118c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 8128c2ecf20Sopenharmony_ci struct renesas_usbhs_driver_pipe_config *pipe_configs = 8138c2ecf20Sopenharmony_ci usbhs_get_dparam(priv, pipe_configs); 8148c2ecf20Sopenharmony_ci int pipe_size = usbhs_get_dparam(priv, pipe_size); 8158c2ecf20Sopenharmony_ci int i; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* This driver expects 1st pipe is DCP */ 8188c2ecf20Sopenharmony_ci if (pipe_configs[0].type != USB_ENDPOINT_XFER_CONTROL) { 8198c2ecf20Sopenharmony_ci dev_err(dev, "1st PIPE is not DCP\n"); 8208c2ecf20Sopenharmony_ci return -EINVAL; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci info->pipe = kcalloc(pipe_size, sizeof(struct usbhs_pipe), 8248c2ecf20Sopenharmony_ci GFP_KERNEL); 8258c2ecf20Sopenharmony_ci if (!info->pipe) 8268c2ecf20Sopenharmony_ci return -ENOMEM; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci info->size = pipe_size; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* 8318c2ecf20Sopenharmony_ci * init pipe 8328c2ecf20Sopenharmony_ci */ 8338c2ecf20Sopenharmony_ci usbhs_for_each_pipe_with_dcp(pipe, priv, i) { 8348c2ecf20Sopenharmony_ci pipe->priv = priv; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci usbhs_pipe_type(pipe) = 8378c2ecf20Sopenharmony_ci pipe_configs[i].type & USB_ENDPOINT_XFERTYPE_MASK; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci dev_dbg(dev, "pipe %x\t: %s\n", 8408c2ecf20Sopenharmony_ci i, usbhsp_pipe_name[pipe_configs[i].type]); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return 0; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_civoid usbhs_pipe_remove(struct usbhs_priv *priv) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci kfree(info->pipe); 8518c2ecf20Sopenharmony_ci} 852