162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Renesas USB driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Renesas Solutions Corp. 662306a36Sopenharmony_ci * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include "common.h" 1162306a36Sopenharmony_ci#include "pipe.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * macros 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci#define usbhsp_addr_offset(p) ((usbhs_pipe_number(p) - 1) * 2) 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define usbhsp_flags_set(p, f) ((p)->flags |= USBHS_PIPE_FLAGS_##f) 1962306a36Sopenharmony_ci#define usbhsp_flags_clr(p, f) ((p)->flags &= ~USBHS_PIPE_FLAGS_##f) 2062306a36Sopenharmony_ci#define usbhsp_flags_has(p, f) ((p)->flags & USBHS_PIPE_FLAGS_##f) 2162306a36Sopenharmony_ci#define usbhsp_flags_init(p) do {(p)->flags = 0; } while (0) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * for debug 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_cistatic char *usbhsp_pipe_name[] = { 2762306a36Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = "DCP", 2862306a36Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = "BULK", 2962306a36Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = "INT", 3062306a36Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = "ISO", 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cichar *usbhs_pipe_name(struct usbhs_pipe *pipe) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci return usbhsp_pipe_name[usbhs_pipe_type(pipe)]; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic struct renesas_usbhs_driver_pipe_config 3962306a36Sopenharmony_ci*usbhsp_get_pipe_config(struct usbhs_priv *priv, int pipe_num) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct renesas_usbhs_driver_pipe_config *pipe_configs = 4262306a36Sopenharmony_ci usbhs_get_dparam(priv, pipe_configs); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return &pipe_configs[pipe_num]; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * DCPCTR/PIPEnCTR functions 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_cistatic void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 5362306a36Sopenharmony_ci int offset = usbhsp_addr_offset(pipe); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 5662306a36Sopenharmony_ci usbhs_bset(priv, DCPCTR, mask, val); 5762306a36Sopenharmony_ci else 5862306a36Sopenharmony_ci usbhs_bset(priv, PIPEnCTR + offset, mask, val); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 6462306a36Sopenharmony_ci int offset = usbhsp_addr_offset(pipe); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 6762306a36Sopenharmony_ci return usbhs_read(priv, DCPCTR); 6862306a36Sopenharmony_ci else 6962306a36Sopenharmony_ci return usbhs_read(priv, PIPEnCTR + offset); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * DCP/PIPE functions 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_cistatic void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe, 7662306a36Sopenharmony_ci u16 dcp_reg, u16 pipe_reg, 7762306a36Sopenharmony_ci u16 mask, u16 val) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 8262306a36Sopenharmony_ci usbhs_bset(priv, dcp_reg, mask, val); 8362306a36Sopenharmony_ci else 8462306a36Sopenharmony_ci usbhs_bset(priv, pipe_reg, mask, val); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic u16 __usbhsp_pipe_xxx_get(struct usbhs_pipe *pipe, 8862306a36Sopenharmony_ci u16 dcp_reg, u16 pipe_reg) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 9362306a36Sopenharmony_ci return usbhs_read(priv, dcp_reg); 9462306a36Sopenharmony_ci else 9562306a36Sopenharmony_ci return usbhs_read(priv, pipe_reg); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* 9962306a36Sopenharmony_ci * DCPCFG/PIPECFG functions 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_cistatic void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, DCPCFG, PIPECFG, mask, val); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic u16 usbhsp_pipe_cfg_get(struct usbhs_pipe *pipe) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci return __usbhsp_pipe_xxx_get(pipe, DCPCFG, PIPECFG); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci * PIPEnTRN/PIPEnTRE functions 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_cistatic void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 11762306a36Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 11862306a36Sopenharmony_ci int num = usbhs_pipe_number(pipe); 11962306a36Sopenharmony_ci u16 reg; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* 12262306a36Sopenharmony_ci * It is impossible to calculate address, 12362306a36Sopenharmony_ci * since PIPEnTRN addresses were mapped randomly. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci#define CASE_PIPExTRN(a) \ 12662306a36Sopenharmony_ci case 0x ## a: \ 12762306a36Sopenharmony_ci reg = PIPE ## a ## TRN; \ 12862306a36Sopenharmony_ci break; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci switch (num) { 13162306a36Sopenharmony_ci CASE_PIPExTRN(1); 13262306a36Sopenharmony_ci CASE_PIPExTRN(2); 13362306a36Sopenharmony_ci CASE_PIPExTRN(3); 13462306a36Sopenharmony_ci CASE_PIPExTRN(4); 13562306a36Sopenharmony_ci CASE_PIPExTRN(5); 13662306a36Sopenharmony_ci CASE_PIPExTRN(B); 13762306a36Sopenharmony_ci CASE_PIPExTRN(C); 13862306a36Sopenharmony_ci CASE_PIPExTRN(D); 13962306a36Sopenharmony_ci CASE_PIPExTRN(E); 14062306a36Sopenharmony_ci CASE_PIPExTRN(F); 14162306a36Sopenharmony_ci CASE_PIPExTRN(9); 14262306a36Sopenharmony_ci CASE_PIPExTRN(A); 14362306a36Sopenharmony_ci default: 14462306a36Sopenharmony_ci dev_err(dev, "unknown pipe (%d)\n", num); 14562306a36Sopenharmony_ci return; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void usbhsp_pipe_tre_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 15362306a36Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 15462306a36Sopenharmony_ci int num = usbhs_pipe_number(pipe); 15562306a36Sopenharmony_ci u16 reg; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * It is impossible to calculate address, 15962306a36Sopenharmony_ci * since PIPEnTRE addresses were mapped randomly. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci#define CASE_PIPExTRE(a) \ 16262306a36Sopenharmony_ci case 0x ## a: \ 16362306a36Sopenharmony_ci reg = PIPE ## a ## TRE; \ 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci switch (num) { 16762306a36Sopenharmony_ci CASE_PIPExTRE(1); 16862306a36Sopenharmony_ci CASE_PIPExTRE(2); 16962306a36Sopenharmony_ci CASE_PIPExTRE(3); 17062306a36Sopenharmony_ci CASE_PIPExTRE(4); 17162306a36Sopenharmony_ci CASE_PIPExTRE(5); 17262306a36Sopenharmony_ci CASE_PIPExTRE(B); 17362306a36Sopenharmony_ci CASE_PIPExTRE(C); 17462306a36Sopenharmony_ci CASE_PIPExTRE(D); 17562306a36Sopenharmony_ci CASE_PIPExTRE(E); 17662306a36Sopenharmony_ci CASE_PIPExTRE(F); 17762306a36Sopenharmony_ci CASE_PIPExTRE(9); 17862306a36Sopenharmony_ci CASE_PIPExTRE(A); 17962306a36Sopenharmony_ci default: 18062306a36Sopenharmony_ci dev_err(dev, "unknown pipe (%d)\n", num); 18162306a36Sopenharmony_ci return; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* 18862306a36Sopenharmony_ci * PIPEBUF 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_cistatic void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 19362306a36Sopenharmony_ci return; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, 0, PIPEBUF, mask, val); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* 19962306a36Sopenharmony_ci * DCPMAXP/PIPEMAXP 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_cistatic void usbhsp_pipe_maxp_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci __usbhsp_pipe_xxx_set(pipe, DCPMAXP, PIPEMAXP, mask, val); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* 20762306a36Sopenharmony_ci * pipe control functions 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistatic void usbhsp_pipe_select(struct usbhs_pipe *pipe) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * On pipe, this is necessary before 21562306a36Sopenharmony_ci * accesses to below registers. 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * PIPESEL : usbhsp_pipe_select 21862306a36Sopenharmony_ci * PIPECFG : usbhsp_pipe_cfg_xxx 21962306a36Sopenharmony_ci * PIPEBUF : usbhsp_pipe_buf_xxx 22062306a36Sopenharmony_ci * PIPEMAXP : usbhsp_pipe_maxp_xxx 22162306a36Sopenharmony_ci * PIPEPERI 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* 22562306a36Sopenharmony_ci * if pipe is dcp, no pipe is selected. 22662306a36Sopenharmony_ci * it is no problem, because dcp have its register 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci usbhs_write(priv, PIPESEL, 0xF & usbhs_pipe_number(pipe)); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 23462306a36Sopenharmony_ci int timeout = 1024; 23562306a36Sopenharmony_ci u16 mask = usbhs_mod_is_host(priv) ? (CSSTS | PID_MASK) : PID_MASK; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* 23862306a36Sopenharmony_ci * make sure.... 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is 24162306a36Sopenharmony_ci * specified by the CURPIPE bits. 24262306a36Sopenharmony_ci * When changing the setting of this bit after changing 24362306a36Sopenharmony_ci * the PID bits for the selected pipe from BUF to NAK, 24462306a36Sopenharmony_ci * check that CSSTS = 0 and PBUSY = 0. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* 24862306a36Sopenharmony_ci * CURPIPE bit = 0 24962306a36Sopenharmony_ci * 25062306a36Sopenharmony_ci * see also 25162306a36Sopenharmony_ci * "Operation" 25262306a36Sopenharmony_ci * - "Pipe Control" 25362306a36Sopenharmony_ci * - "Pipe Control Registers Switching Procedure" 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_ci usbhs_write(priv, CFIFOSEL, 0); 25662306a36Sopenharmony_ci usbhs_pipe_disable(pipe); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci do { 25962306a36Sopenharmony_ci if (!(usbhsp_pipectrl_get(pipe) & mask)) 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci udelay(10); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci } while (timeout--); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return -EBUSY; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ciint usbhs_pipe_is_accessible(struct usbhs_pipe *pipe) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci u16 val; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci val = usbhsp_pipectrl_get(pipe); 27462306a36Sopenharmony_ci if (val & BSTS) 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return -EBUSY; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cibool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci u16 val; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Do not support for DCP pipe */ 28562306a36Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 28662306a36Sopenharmony_ci return false; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci val = usbhsp_pipectrl_get(pipe); 28962306a36Sopenharmony_ci if (val & INBUFM) 29062306a36Sopenharmony_ci return true; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return false; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* 29662306a36Sopenharmony_ci * PID ctrl 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_cistatic void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci u16 pid = usbhsp_pipectrl_get(pipe); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci pid &= PID_MASK; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci * see 30662306a36Sopenharmony_ci * "Pipe n Control Register" - "PID" 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci switch (pid) { 30962306a36Sopenharmony_ci case PID_STALL11: 31062306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); 31162306a36Sopenharmony_ci fallthrough; 31262306a36Sopenharmony_ci case PID_STALL10: 31362306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_civoid usbhs_pipe_disable(struct usbhs_pipe *pipe) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci int timeout = 1024; 32062306a36Sopenharmony_ci u16 val; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* see "Pipe n Control Register" - "PID" */ 32362306a36Sopenharmony_ci __usbhsp_pid_try_nak_if_stall(pipe); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci do { 32862306a36Sopenharmony_ci val = usbhsp_pipectrl_get(pipe); 32962306a36Sopenharmony_ci val &= PBUSY; 33062306a36Sopenharmony_ci if (!val) 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci udelay(10); 33462306a36Sopenharmony_ci } while (timeout--); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_civoid usbhs_pipe_enable(struct usbhs_pipe *pipe) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci /* see "Pipe n Control Register" - "PID" */ 34062306a36Sopenharmony_ci __usbhsp_pid_try_nak_if_stall(pipe); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_BUF); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_civoid usbhs_pipe_stall(struct usbhs_pipe *pipe) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci u16 pid = usbhsp_pipectrl_get(pipe); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci pid &= PID_MASK; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* 35262306a36Sopenharmony_ci * see 35362306a36Sopenharmony_ci * "Pipe n Control Register" - "PID" 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci switch (pid) { 35662306a36Sopenharmony_ci case PID_NAK: 35762306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci case PID_BUF: 36062306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL11); 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ciint usbhs_pipe_is_stall(struct usbhs_pipe *pipe) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return (int)(pid == PID_STALL10 || pid == PID_STALL11); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_civoid usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) 37562306a36Sopenharmony_ci return; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* 37862306a36Sopenharmony_ci * clear and disable transfer counter for IN/OUT pipe 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* 38362306a36Sopenharmony_ci * Only IN direction bulk pipe can use transfer count. 38462306a36Sopenharmony_ci * Without using this function, 38562306a36Sopenharmony_ci * received data will break if it was large data size. 38662306a36Sopenharmony_ci * see PIPEnTRN/PIPEnTRE for detail 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ci if (usbhs_pipe_is_dir_in(pipe)) { 38962306a36Sopenharmony_ci int maxp = usbhs_pipe_get_maxpacket(pipe); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci usbhsp_pipe_trn_set(pipe, 0xffff, DIV_ROUND_UP(len, maxp)); 39262306a36Sopenharmony_ci usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */ 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci/* 39862306a36Sopenharmony_ci * pipe setup 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_cistatic int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host, 40162306a36Sopenharmony_ci int dir_in, u16 *pipecfg) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci u16 type = 0; 40462306a36Sopenharmony_ci u16 bfre = 0; 40562306a36Sopenharmony_ci u16 dblb = 0; 40662306a36Sopenharmony_ci u16 cntmd = 0; 40762306a36Sopenharmony_ci u16 dir = 0; 40862306a36Sopenharmony_ci u16 epnum = 0; 40962306a36Sopenharmony_ci u16 shtnak = 0; 41062306a36Sopenharmony_ci static const u16 type_array[] = { 41162306a36Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = TYPE_BULK, 41262306a36Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = TYPE_INT, 41362306a36Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = TYPE_ISO, 41462306a36Sopenharmony_ci }; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 41762306a36Sopenharmony_ci return -EINVAL; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * PIPECFG 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * see 42362306a36Sopenharmony_ci * - "Register Descriptions" - "PIPECFG" register 42462306a36Sopenharmony_ci * - "Features" - "Pipe configuration" 42562306a36Sopenharmony_ci * - "Operation" - "Pipe Control" 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* TYPE */ 42962306a36Sopenharmony_ci type = type_array[usbhs_pipe_type(pipe)]; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* BFRE */ 43262306a36Sopenharmony_ci if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) || 43362306a36Sopenharmony_ci usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) 43462306a36Sopenharmony_ci bfre = 0; /* FIXME */ 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* DBLB: see usbhs_pipe_config_update() */ 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* CNTMD */ 43962306a36Sopenharmony_ci if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) 44062306a36Sopenharmony_ci cntmd = 0; /* FIXME */ 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* DIR */ 44362306a36Sopenharmony_ci if (dir_in) 44462306a36Sopenharmony_ci usbhsp_flags_set(pipe, IS_DIR_HOST); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (!!is_host ^ !!dir_in) 44762306a36Sopenharmony_ci dir |= DIR_OUT; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (!dir) 45062306a36Sopenharmony_ci usbhsp_flags_set(pipe, IS_DIR_IN); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* SHTNAK */ 45362306a36Sopenharmony_ci if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) && 45462306a36Sopenharmony_ci !dir) 45562306a36Sopenharmony_ci shtnak = SHTNAK; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* EPNUM */ 45862306a36Sopenharmony_ci epnum = 0; /* see usbhs_pipe_config_update() */ 45962306a36Sopenharmony_ci *pipecfg = type | 46062306a36Sopenharmony_ci bfre | 46162306a36Sopenharmony_ci dblb | 46262306a36Sopenharmony_ci cntmd | 46362306a36Sopenharmony_ci dir | 46462306a36Sopenharmony_ci shtnak | 46562306a36Sopenharmony_ci epnum; 46662306a36Sopenharmony_ci return 0; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 47262306a36Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 47362306a36Sopenharmony_ci int pipe_num = usbhs_pipe_number(pipe); 47462306a36Sopenharmony_ci u16 buff_size; 47562306a36Sopenharmony_ci u16 bufnmb; 47662306a36Sopenharmony_ci u16 bufnmb_cnt; 47762306a36Sopenharmony_ci struct renesas_usbhs_driver_pipe_config *pipe_config = 47862306a36Sopenharmony_ci usbhsp_get_pipe_config(priv, pipe_num); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* 48162306a36Sopenharmony_ci * PIPEBUF 48262306a36Sopenharmony_ci * 48362306a36Sopenharmony_ci * see 48462306a36Sopenharmony_ci * - "Register Descriptions" - "PIPEBUF" register 48562306a36Sopenharmony_ci * - "Features" - "Pipe configuration" 48662306a36Sopenharmony_ci * - "Operation" - "FIFO Buffer Memory" 48762306a36Sopenharmony_ci * - "Operation" - "Pipe Control" 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_ci buff_size = pipe_config->bufsize; 49062306a36Sopenharmony_ci bufnmb = pipe_config->bufnum; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* change buff_size to register value */ 49362306a36Sopenharmony_ci bufnmb_cnt = (buff_size / 64) - 1; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci dev_dbg(dev, "pipe : %d : buff_size 0x%x: bufnmb 0x%x\n", 49662306a36Sopenharmony_ci pipe_num, buff_size, bufnmb); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return (0x1f & bufnmb_cnt) << 10 | 49962306a36Sopenharmony_ci (0xff & bufnmb) << 0; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_civoid usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, 50362306a36Sopenharmony_ci u16 epnum, u16 maxp) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 50662306a36Sopenharmony_ci int pipe_num = usbhs_pipe_number(pipe); 50762306a36Sopenharmony_ci struct renesas_usbhs_driver_pipe_config *pipe_config = 50862306a36Sopenharmony_ci usbhsp_get_pipe_config(priv, pipe_num); 50962306a36Sopenharmony_ci u16 dblb = pipe_config->double_buf ? DBLB : 0; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (devsel > 0xA) { 51262306a36Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci dev_err(dev, "devsel error %d\n", devsel); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci devsel = 0; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci usbhsp_pipe_barrier(pipe); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci pipe->maxp = maxp; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci usbhsp_pipe_select(pipe); 52462306a36Sopenharmony_ci usbhsp_pipe_maxp_set(pipe, 0xFFFF, 52562306a36Sopenharmony_ci (devsel << 12) | 52662306a36Sopenharmony_ci maxp); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (!usbhs_pipe_is_dcp(pipe)) 52962306a36Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, 0x000F | DBLB, epnum | dblb); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci/* 53362306a36Sopenharmony_ci * pipe control 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_ciint usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci /* 53862306a36Sopenharmony_ci * see 53962306a36Sopenharmony_ci * usbhs_pipe_config_update() 54062306a36Sopenharmony_ci * usbhs_dcp_malloc() 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_ci return pipe->maxp; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ciint usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci return usbhsp_flags_has(pipe, IS_DIR_IN); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ciint usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci return usbhsp_flags_has(pipe, IS_DIR_HOST); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ciint usbhs_pipe_is_running(struct usbhs_pipe *pipe) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci return usbhsp_flags_has(pipe, IS_RUNNING); 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_civoid usbhs_pipe_running(struct usbhs_pipe *pipe, int running) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci if (running) 56362306a36Sopenharmony_ci usbhsp_flags_set(pipe, IS_RUNNING); 56462306a36Sopenharmony_ci else 56562306a36Sopenharmony_ci usbhsp_flags_clr(pipe, IS_RUNNING); 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_civoid usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci u16 mask = (SQCLR | SQSET); 57162306a36Sopenharmony_ci u16 val; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* 57462306a36Sopenharmony_ci * sequence 57562306a36Sopenharmony_ci * 0 : data0 57662306a36Sopenharmony_ci * 1 : data1 57762306a36Sopenharmony_ci * -1 : no change 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_ci switch (sequence) { 58062306a36Sopenharmony_ci case 0: 58162306a36Sopenharmony_ci val = SQCLR; 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci case 1: 58462306a36Sopenharmony_ci val = SQSET; 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci default: 58762306a36Sopenharmony_ci return; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, mask, val); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic int usbhs_pipe_get_data_sequence(struct usbhs_pipe *pipe) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci return !!(usbhsp_pipectrl_get(pipe) & SQMON); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_civoid usbhs_pipe_clear(struct usbhs_pipe *pipe) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) { 60162306a36Sopenharmony_ci usbhs_fifo_clear_dcp(pipe); 60262306a36Sopenharmony_ci } else { 60362306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); 60462306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, ACLRM, 0); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci/* Should call usbhsp_pipe_select() before */ 60962306a36Sopenharmony_civoid usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe, 61062306a36Sopenharmony_ci int needs_bfre, int bfre_enable) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci int sequence; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci usbhsp_pipe_select(pipe); 61562306a36Sopenharmony_ci sequence = usbhs_pipe_get_data_sequence(pipe); 61662306a36Sopenharmony_ci if (needs_bfre) 61762306a36Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, BFRE, bfre_enable ? BFRE : 0); 61862306a36Sopenharmony_ci usbhs_pipe_clear(pipe); 61962306a36Sopenharmony_ci usbhs_pipe_data_sequence(pipe, sequence); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_civoid usbhs_pipe_config_change_bfre(struct usbhs_pipe *pipe, int enable) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci if (usbhs_pipe_is_dcp(pipe)) 62562306a36Sopenharmony_ci return; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci usbhsp_pipe_select(pipe); 62862306a36Sopenharmony_ci /* check if the driver needs to change the BFRE value */ 62962306a36Sopenharmony_ci if (!(enable ^ !!(usbhsp_pipe_cfg_get(pipe) & BFRE))) 63062306a36Sopenharmony_ci return; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci usbhs_pipe_clear_without_sequence(pipe, 1, enable); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct usbhs_pipe *pos, *pipe; 63862306a36Sopenharmony_ci int i; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* 64162306a36Sopenharmony_ci * find target pipe 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_ci pipe = NULL; 64462306a36Sopenharmony_ci usbhs_for_each_pipe_with_dcp(pos, priv, i) { 64562306a36Sopenharmony_ci if (!usbhs_pipe_type_is(pos, type)) 64662306a36Sopenharmony_ci continue; 64762306a36Sopenharmony_ci if (usbhsp_flags_has(pos, IS_USED)) 64862306a36Sopenharmony_ci continue; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci pipe = pos; 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (!pipe) 65562306a36Sopenharmony_ci return NULL; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* 65862306a36Sopenharmony_ci * initialize pipe flags 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ci usbhsp_flags_init(pipe); 66162306a36Sopenharmony_ci usbhsp_flags_set(pipe, IS_USED); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci return pipe; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic void usbhsp_put_pipe(struct usbhs_pipe *pipe) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci usbhsp_flags_init(pipe); 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_civoid usbhs_pipe_init(struct usbhs_priv *priv, 67262306a36Sopenharmony_ci int (*dma_map_ctrl)(struct device *dma_dev, 67362306a36Sopenharmony_ci struct usbhs_pkt *pkt, int map)) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); 67662306a36Sopenharmony_ci struct usbhs_pipe *pipe; 67762306a36Sopenharmony_ci int i; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci usbhs_for_each_pipe_with_dcp(pipe, priv, i) { 68062306a36Sopenharmony_ci usbhsp_flags_init(pipe); 68162306a36Sopenharmony_ci pipe->fifo = NULL; 68262306a36Sopenharmony_ci pipe->mod_private = NULL; 68362306a36Sopenharmony_ci INIT_LIST_HEAD(&pipe->list); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* pipe force init */ 68662306a36Sopenharmony_ci usbhs_pipe_clear(pipe); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci info->dma_map_ctrl = dma_map_ctrl; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistruct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, 69362306a36Sopenharmony_ci int endpoint_type, 69462306a36Sopenharmony_ci int dir_in) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 69762306a36Sopenharmony_ci struct usbhs_pipe *pipe; 69862306a36Sopenharmony_ci int is_host = usbhs_mod_is_host(priv); 69962306a36Sopenharmony_ci int ret; 70062306a36Sopenharmony_ci u16 pipecfg, pipebuf; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci pipe = usbhsp_get_pipe(priv, endpoint_type); 70362306a36Sopenharmony_ci if (!pipe) { 70462306a36Sopenharmony_ci dev_err(dev, "can't get pipe (%s)\n", 70562306a36Sopenharmony_ci usbhsp_pipe_name[endpoint_type]); 70662306a36Sopenharmony_ci return NULL; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci INIT_LIST_HEAD(&pipe->list); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci usbhs_pipe_disable(pipe); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* make sure pipe is not busy */ 71462306a36Sopenharmony_ci ret = usbhsp_pipe_barrier(pipe); 71562306a36Sopenharmony_ci if (ret < 0) { 71662306a36Sopenharmony_ci dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe)); 71762306a36Sopenharmony_ci return NULL; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) { 72162306a36Sopenharmony_ci dev_err(dev, "can't setup pipe\n"); 72262306a36Sopenharmony_ci return NULL; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci pipebuf = usbhsp_setup_pipebuff(pipe); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci usbhsp_pipe_select(pipe); 72862306a36Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg); 72962306a36Sopenharmony_ci usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf); 73062306a36Sopenharmony_ci usbhs_pipe_clear(pipe); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci usbhs_pipe_sequence_data0(pipe); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci dev_dbg(dev, "enable pipe %d : %s (%s)\n", 73562306a36Sopenharmony_ci usbhs_pipe_number(pipe), 73662306a36Sopenharmony_ci usbhs_pipe_name(pipe), 73762306a36Sopenharmony_ci usbhs_pipe_is_dir_in(pipe) ? "in" : "out"); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* 74062306a36Sopenharmony_ci * epnum / maxp are still not set to this pipe. 74162306a36Sopenharmony_ci * call usbhs_pipe_config_update() after this function !! 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return pipe; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_civoid usbhs_pipe_free(struct usbhs_pipe *pipe) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci usbhsp_pipe_select(pipe); 75062306a36Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, 0xFFFF, 0); 75162306a36Sopenharmony_ci usbhsp_put_pipe(pipe); 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_civoid usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci if (pipe->fifo) 75762306a36Sopenharmony_ci pipe->fifo->pipe = NULL; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci pipe->fifo = fifo; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (fifo) 76262306a36Sopenharmony_ci fifo->pipe = pipe; 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci/* 76762306a36Sopenharmony_ci * dcp control 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_cistruct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct usbhs_pipe *pipe; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci pipe = usbhsp_get_pipe(priv, USB_ENDPOINT_XFER_CONTROL); 77462306a36Sopenharmony_ci if (!pipe) 77562306a36Sopenharmony_ci return NULL; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci INIT_LIST_HEAD(&pipe->list); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* 78062306a36Sopenharmony_ci * call usbhs_pipe_config_update() after this function !! 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return pipe; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_civoid usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci WARN_ON(!usbhs_pipe_is_dcp(pipe)); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci usbhs_pipe_enable(pipe); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (!usbhs_mod_is_host(priv)) /* funconly */ 79562306a36Sopenharmony_ci usbhsp_pipectrl_set(pipe, CCPL, CCPL); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_civoid usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci usbhsp_pipe_cfg_set(pipe, DIR_OUT, 80162306a36Sopenharmony_ci dir_out ? DIR_OUT : 0); 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci/* 80562306a36Sopenharmony_ci * pipe module function 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_ciint usbhs_pipe_probe(struct usbhs_priv *priv) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); 81062306a36Sopenharmony_ci struct usbhs_pipe *pipe; 81162306a36Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 81262306a36Sopenharmony_ci struct renesas_usbhs_driver_pipe_config *pipe_configs = 81362306a36Sopenharmony_ci usbhs_get_dparam(priv, pipe_configs); 81462306a36Sopenharmony_ci int pipe_size = usbhs_get_dparam(priv, pipe_size); 81562306a36Sopenharmony_ci int i; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* This driver expects 1st pipe is DCP */ 81862306a36Sopenharmony_ci if (pipe_configs[0].type != USB_ENDPOINT_XFER_CONTROL) { 81962306a36Sopenharmony_ci dev_err(dev, "1st PIPE is not DCP\n"); 82062306a36Sopenharmony_ci return -EINVAL; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci info->pipe = kcalloc(pipe_size, sizeof(struct usbhs_pipe), 82462306a36Sopenharmony_ci GFP_KERNEL); 82562306a36Sopenharmony_ci if (!info->pipe) 82662306a36Sopenharmony_ci return -ENOMEM; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci info->size = pipe_size; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* 83162306a36Sopenharmony_ci * init pipe 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_ci usbhs_for_each_pipe_with_dcp(pipe, priv, i) { 83462306a36Sopenharmony_ci pipe->priv = priv; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci usbhs_pipe_type(pipe) = 83762306a36Sopenharmony_ci pipe_configs[i].type & USB_ENDPOINT_XFERTYPE_MASK; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci dev_dbg(dev, "pipe %x\t: %s\n", 84062306a36Sopenharmony_ci i, usbhsp_pipe_name[pipe_configs[i].type]); 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_civoid usbhs_pipe_remove(struct usbhs_priv *priv) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci kfree(info->pipe); 85162306a36Sopenharmony_ci} 852