123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886 |
- diff -Nur linux-4.0.3.orig/arch/cris/arch-v32/drivers/Kconfig linux-4.0.3/arch/cris/arch-v32/drivers/Kconfig
- --- linux-4.0.3.orig/arch/cris/arch-v32/drivers/Kconfig 2015-05-13 14:14:53.000000000 +0200
- +++ linux-4.0.3/arch/cris/arch-v32/drivers/Kconfig 2015-05-25 17:20:55.000000000 +0200
- @@ -49,24 +49,261 @@
- if you do not need DMA to something else.
- ser0 can use dma4 or dma6 for output and dma5 or dma7 for input.
-
- +choice
- + prompt "Ser0 default port type "
- + depends on ETRAX_SERIAL_PORT0
- + default ETRAX_SERIAL_PORT0_TYPE_232
- + help
- + Type of serial port.
- +
- +config ETRAX_SERIAL_PORT0_TYPE_232
- + bool "Ser0 is a RS-232 port"
- + help
- + Configure serial port 0 to be a RS-232 port.
- +
- +config ETRAX_SERIAL_PORT0_TYPE_485HD
- + bool "Ser0 is a half duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 0 to be a half duplex (two wires) RS-485 port.
- +
- +config ETRAX_SERIAL_PORT0_TYPE_485FD
- + bool "Ser0 is a full duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 0 to be a full duplex (four wires) RS-485 port.
- +endchoice
- +
- +config ETRAX_SER0_DTR_BIT
- + string "Ser 0 DTR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT0
- +
- +config ETRAX_SER0_RI_BIT
- + string "Ser 0 RI bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT0
- +
- +config ETRAX_SER0_DSR_BIT
- + string "Ser 0 DSR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT0
- +
- +config ETRAX_SER0_CD_BIT
- + string "Ser 0 CD bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT0
- +
- config ETRAX_SERIAL_PORT1
- bool "Serial port 1 enabled"
- depends on ETRAXFS_SERIAL
- help
- Enables the ETRAX FS serial driver for ser1 (ttyS1).
-
- +choice
- + prompt "Ser1 default port type"
- + depends on ETRAX_SERIAL_PORT1
- + default ETRAX_SERIAL_PORT1_TYPE_232
- + help
- + Type of serial port.
- +
- +config ETRAX_SERIAL_PORT1_TYPE_232
- + bool "Ser1 is a RS-232 port"
- + help
- + Configure serial port 1 to be a RS-232 port.
- +
- +config ETRAX_SERIAL_PORT1_TYPE_485HD
- + bool "Ser1 is a half duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 1 to be a half duplex (two wires) RS-485 port.
- +
- +config ETRAX_SERIAL_PORT1_TYPE_485FD
- + bool "Ser1 is a full duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 1 to be a full duplex (four wires) RS-485 port.
- +endchoice
- +
- +config ETRAX_SER1_DTR_BIT
- + string "Ser 1 DTR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT1
- +
- +config ETRAX_SER1_RI_BIT
- + string "Ser 1 RI bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT1
- +
- +config ETRAX_SER1_DSR_BIT
- + string "Ser 1 DSR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT1
- +
- +config ETRAX_SER1_CD_BIT
- + string "Ser 1 CD bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT1
- +
- config ETRAX_SERIAL_PORT2
- bool "Serial port 2 enabled"
- depends on ETRAXFS_SERIAL
- help
- Enables the ETRAX FS serial driver for ser2 (ttyS2).
-
- +choice
- + prompt "Ser2 default port type"
- + depends on ETRAX_SERIAL_PORT2
- + default ETRAX_SERIAL_PORT2_TYPE_232
- + help
- + What DMA channel to use for ser2
- +
- +config ETRAX_SERIAL_PORT2_TYPE_232
- + bool "Ser2 is a RS-232 port"
- + help
- + Configure serial port 2 to be a RS-232 port.
- +
- +config ETRAX_SERIAL_PORT2_TYPE_485HD
- + bool "Ser2 is a half duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 2 to be a half duplex (two wires) RS-485 port.
- +
- +config ETRAX_SERIAL_PORT2_TYPE_485FD
- + bool "Ser2 is a full duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 2 to be a full duplex (four wires) RS-485 port.
- +endchoice
- +
- +
- +config ETRAX_SER2_DTR_BIT
- + string "Ser 2 DTR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT2
- +
- +config ETRAX_SER2_RI_BIT
- + string "Ser 2 RI bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT2
- +
- +config ETRAX_SER2_DSR_BIT
- + string "Ser 2 DSR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT2
- +
- +config ETRAX_SER2_CD_BIT
- + string "Ser 2 CD bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT2
- +
- config ETRAX_SERIAL_PORT3
- bool "Serial port 3 enabled"
- depends on ETRAXFS_SERIAL
- help
- Enables the ETRAX FS serial driver for ser3 (ttyS3).
-
- +choice
- + prompt "Ser3 default port type"
- + depends on ETRAX_SERIAL_PORT3
- + default ETRAX_SERIAL_PORT3_TYPE_232
- + help
- + What DMA channel to use for ser3.
- +
- +config ETRAX_SERIAL_PORT3_TYPE_232
- + bool "Ser3 is a RS-232 port"
- + help
- + Configure serial port 3 to be a RS-232 port.
- +
- +config ETRAX_SERIAL_PORT3_TYPE_485HD
- + bool "Ser3 is a half duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 3 to be a half duplex (two wires) RS-485 port.
- +
- +config ETRAX_SERIAL_PORT3_TYPE_485FD
- + bool "Ser3 is a full duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 3 to be a full duplex (four wires) RS-485 port.
- +endchoice
- +
- +config ETRAX_SER3_DTR_BIT
- + string "Ser 3 DTR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT3
- +
- +config ETRAX_SER3_RI_BIT
- + string "Ser 3 RI bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT3
- +
- +config ETRAX_SER3_DSR_BIT
- + string "Ser 3 DSR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT3
- +
- +config ETRAX_SER3_CD_BIT
- + string "Ser 3 CD bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT3
- +
- +config ETRAX_SERIAL_PORT4
- + bool "Serial port 4 enabled"
- + depends on ETRAXFS_SERIAL && CRIS_MACH_ARTPEC3
- + help
- + Enables the ETRAX FS serial driver for ser4 (ttyS4).
- +
- +choice
- + prompt "Ser4 default port type"
- + depends on ETRAX_SERIAL_PORT4
- + default ETRAX_SERIAL_PORT4_TYPE_232
- + help
- + What DMA channel to use for ser4.
- +
- +config ETRAX_SERIAL_PORT4_TYPE_232
- + bool "Ser4 is a RS-232 port"
- + help
- + Configure serial port 4 to be a RS-232 port.
- +
- +config ETRAX_SERIAL_PORT4_TYPE_485HD
- + bool "Ser4 is a half duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 4 to be a half duplex (two wires) RS-485 port.
- +
- +config ETRAX_SERIAL_PORT4_TYPE_485FD
- + bool "Ser4 is a full duplex RS-485 port"
- + depends on ETRAX_RS485
- + help
- + Configure serial port 4 to be a full duplex (four wires) RS-485 port.
- +endchoice
- +
- +choice
- + prompt "Ser4 DMA in channel "
- + depends on ETRAX_SERIAL_PORT4
- + default ETRAX_SERIAL_PORT4_NO_DMA_IN
- + help
- + What DMA channel to use for ser4.
- +
- +
- +config ETRAX_SERIAL_PORT4_NO_DMA_IN
- + bool "Ser4 uses no DMA for input"
- + help
- + Do not use DMA for ser4 input.
- +
- +config ETRAX_SERIAL_PORT4_DMA9_IN
- + bool "Ser4 uses DMA9 for input"
- + depends on ETRAX_SERIAL_PORT4
- + help
- + Enables the DMA9 input channel for ser4 (ttyS4).
- + If you do not enable DMA, an interrupt for each character will be
- + used when receiving data.
- + Normally you want to use DMA, unless you use the DMA channel for
- + something else.
- +
- +endchoice
- +
- +config ETRAX_SER4_DTR_BIT
- + string "Ser 4 DTR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT4
- +
- +config ETRAX_SER4_RI_BIT
- + string "Ser 4 RI bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT4
- +
- +config ETRAX_SER4_DSR_BIT
- + string "Ser 4 DSR bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT4
- +
- +config ETRAX_SER4_CD_BIT
- + string "Ser 4 CD bit (empty = not used)"
- + depends on ETRAX_SERIAL_PORT4
- +
- config ETRAX_SYNCHRONOUS_SERIAL
- bool "Synchronous serial-port support"
- depends on ETRAX_ARCH_V32
- diff -Nur linux-4.0.3.orig/arch/cris/include/uapi/asm/ioctls.h linux-4.0.3/arch/cris/include/uapi/asm/ioctls.h
- --- linux-4.0.3.orig/arch/cris/include/uapi/asm/ioctls.h 2015-05-13 14:14:53.000000000 +0200
- +++ linux-4.0.3/arch/cris/include/uapi/asm/ioctls.h 2015-05-25 17:20:56.000000000 +0200
- @@ -5,6 +5,10 @@
- #define TIOCSERSETRS485 0x5461 /* enable rs-485 (deprecated) */
- #define TIOCSERWRRS485 0x5462 /* write rs-485 */
- #define TIOCSRS485 0x5463 /* enable rs-485 */
- +#define TIOCSERSETRS485FD 0x5464 /* set rs-485 full/half duplex mode */
- +
- +
- +#define TIOCSERSETDIVISOR 0x5465 /* set the divisor for non standard bauds */
-
- #include <asm-generic/ioctls.h>
-
- diff -Nur linux-4.0.3.orig/drivers/tty/serial/crisv32.c linux-4.0.3/drivers/tty/serial/crisv32.c
- --- linux-4.0.3.orig/drivers/tty/serial/crisv32.c 1970-01-01 01:00:00.000000000 +0100
- +++ linux-4.0.3/drivers/tty/serial/crisv32.c 2015-05-25 17:20:56.000000000 +0200
- @@ -0,0 +1,2581 @@
- +/* $Id: crisv32.c,v 1.109 2010-07-09 15:00:44 jespern Exp $
- + *
- + * Serial port driver for the ETRAX FS chip
- + *
- + * Copyright (C) 1998-2006 Axis Communications AB
- + *
- + * Many, many authors. Based once upon a time on serial.c for 16x50.
- + *
- + * Johan Adolfsson - port to ETRAX FS
- + * Mikael Starvik - port to serial_core framework
- + *
- + */
- +
- +#include <linux/module.h>
- +#include <linux/init.h>
- +#include <linux/console.h>
- +#include <linux/types.h>
- +#include <linux/errno.h>
- +#include <linux/serial_core.h>
- +#include <linux/delay.h>
- +#include <linux/slab.h>
- +#include <linux/tty_flip.h>
- +
- +#include <asm/io.h>
- +#include <asm/irq.h>
- +#include <asm/uaccess.h>
- +
- +#include <dma.h>
- +#include <arch/system.h>
- +#include <mach/pinmux.h>
- +#include <hwregs/dma.h>
- +#include <hwregs/reg_rdwr.h>
- +#include <hwregs/ser_defs.h>
- +#include <hwregs/dma_defs.h>
- +#include <hwregs/gio_defs.h>
- +#include <hwregs/intr_vect_defs.h>
- +#include <hwregs/reg_map.h>
- +
- +#define UART_NR CONFIG_ETRAX_SERIAL_PORTS + 1 /* Ports + dummy port */
- +#define SERIAL_RECV_DESCRIPTORS 8
- +
- +/* We only buffer 255 characters here, no need for more tx descriptors. */
- +#define SERIAL_TX_DESCRIPTORS 4
- +
- +/* Kept for experimental purposes. */
- +#define SERIAL_DESCR_BUF_SIZE 256
- +#define regi_NULL 0
- +#define DMA_WAIT_UNTIL_RESET(inst) \
- + do { \
- + reg_dma_rw_stat r; \
- + do { \
- + r = REG_RD(dma, (inst), rw_stat); \
- + } while (r.mode != regk_dma_rst); \
- + } while (0)
- +
- +#define __DMA(ch) regi_dma##ch
- +#define DMA(ch) __DMA(ch)
- +#define DMA_IRQ(ch) (DMA0_INTR_VECT + (ch))
- +
- +/* Macro to set up control lines for a port. */
- +#define SETUP_PINS(port) \
- + if (serial_cris_ports[port].used) { \
- + if (strcmp(CONFIG_ETRAX_SER##port##_DTR_BIT, "")) \
- + crisv32_io_get_name(&serial_cris_ports[port].dtr_pin, \
- + CONFIG_ETRAX_SER##port##_DTR_BIT); \
- + else \
- + serial_cris_ports[port].dtr_pin = dummy_pin; \
- + if (strcmp(CONFIG_ETRAX_SER##port##_DSR_BIT, "")) \
- + crisv32_io_get_name(&serial_cris_ports[port].dsr_pin, \
- + CONFIG_ETRAX_SER##port##_DSR_BIT); \
- + else \
- + serial_cris_ports[port].dsr_pin = dummy_pin; \
- + if (strcmp(CONFIG_ETRAX_SER##port##_RI_BIT, "")) \
- + crisv32_io_get_name(&serial_cris_ports[port].ri_pin, \
- + CONFIG_ETRAX_SER##port##_RI_BIT); \
- + else \
- + serial_cris_ports[port].ri_pin = dummy_pin; \
- + if (strcmp(CONFIG_ETRAX_SER##port##_CD_BIT, "")) \
- + crisv32_io_get_name(&serial_cris_ports[port].cd_pin, \
- + CONFIG_ETRAX_SER##port##_CD_BIT); \
- + else \
- + serial_cris_ports[port].cd_pin = dummy_pin; \
- + }
- +
- +/* Set a serial port register if anything has changed. */
- +#define MODIFY_REG(instance, reg, var) \
- + if (REG_RD_INT(ser, instance, reg) \
- + != REG_TYPE_CONV(int, reg_ser_##reg, var)) \
- + REG_WR(ser, instance, reg, var);
- +
- +/*
- + * Regarding RS485 operation in crisv32 serial driver.
- + * ---------------------------------------------------
- + * RS485 can be run in two modes, full duplex using four wires (485FD) and
- + * half duplex using two wires (485HD). The default mode of each serial port
- + * is configured in the kernel configuration. The available modes are:
- + * RS-232, RS-485 half duplex, and RS-485 full duplex.
- + *
- + * In the 485HD mode the direction of the data bus must be able to switch.
- + * The direction of the transceiver is controlled by the RTS signal. Hence
- + * the auto_rts function in the ETRAX FS chip is enabled in this mode, which
- + * automatically toggle RTS when transmitting. The initial direction of the
- + * port is receiving.
- + *
- + * In the 485FD mode two transceivers will be used, one in each direction.
- + * Usually the hardware can handle both 485HD and 485FD, which implies that
- + * one of the transceivers can change direction. Consequently that transceiver
- + * must be tied to operate in the opposite direction of the other one, setting
- + * and keeping RTS to a fixed value do this.
- + *
- + * There are two special "ioctl" that can configure the ports. These two are
- + * left for backward compatible with older applications. The effects of using
- + * them are described below:
- + * The TIOCSERSETRS485:
- + * This ioctl sets a serial port in 232 mode to 485HD mode or vise versa. The
- + * state of the port is kept when closing the port. Note that this ioctl has no
- + * effect on a serial port in the 485FD mode.
- + * The TIOCSERWRRS485:
- + * This ioctl set a serial port in 232 mode to 485HD mode and writes the data
- + * "included" in the ioctl to the port. The port will then stay in 485HD mode.
- + * Using this ioctl on a serial port in the 485HD mode will transmit the data
- + * without changing the mode. Using this ioctl on a serial port in 485FD mode
- + * will not change the mode and simply send the data using the 485FD mode.
- + */
- +
- +#define TYPE_232 0
- +#define TYPE_485HD 1
- +#define TYPE_485FD 2
- +
- +struct etrax_recv_buffer {
- + struct etrax_recv_buffer *next;
- + unsigned short length;
- + unsigned char error;
- + unsigned char pad;
- +
- + unsigned char buffer[0];
- +};
- +
- +struct uart_cris_port {
- + struct uart_port port;
- +
- + int initialized;
- + int used;
- + int irq;
- +
- + /* Used to check if port enabled as well by testing for zero. */
- + reg_scope_instances regi_ser;
- + reg_scope_instances regi_dmain;
- + reg_scope_instances regi_dmaout;
- +
- + struct crisv32_iopin dtr_pin;
- + struct crisv32_iopin dsr_pin;
- + struct crisv32_iopin ri_pin;
- + struct crisv32_iopin cd_pin;
- +
- + struct dma_descr_context tr_context_descr
- + __attribute__ ((__aligned__(32)));
- + struct dma_descr_data tr_descr[SERIAL_TX_DESCRIPTORS]
- + __attribute__ ((__aligned__(32)));
- + struct dma_descr_context rec_context_descr
- + __attribute__ ((__aligned__(32)));
- + struct dma_descr_data rec_descr[SERIAL_RECV_DESCRIPTORS]
- + __attribute__ ((__aligned__(32)));
- +
- + /* This is the first one in the list the HW is working on now. */
- + struct dma_descr_data* first_tx_descr;
- +
- + /* This is the last one in the list the HW is working on now. */
- + struct dma_descr_data* last_tx_descr;
- +
- + /* This is how many characters the HW is working on now. */
- + unsigned int tx_pending_chars;
- +
- + int tx_started;
- + unsigned int cur_rec_descr;
- + struct etrax_recv_buffer *first_recv_buffer;
- + struct etrax_recv_buffer *last_recv_buffer;
- +
- + unsigned int recv_cnt;
- + unsigned int max_recv_cnt;
- +
- + /* The time for 1 char, in usecs. */
- + unsigned long char_time_usec;
- +
- + /* Last tx usec in the jiffies. */
- + unsigned long last_tx_active_usec;
- +
- + /* Last tx time in jiffies. */
- + unsigned long last_tx_active;
- +
- + /* Last rx usec in the jiffies. */
- + unsigned long last_rx_active_usec;
- +
- + /* Last rx time in jiffies. */
- + unsigned long last_rx_active;
- +
- +#ifdef CONFIG_ETRAX_RS485
- + /* RS-485 support, duh. */
- + struct rs485_control rs485;
- +#endif
- + int port_type;
- + int write_ongoing;
- +};
- +
- +extern struct uart_driver serial_cris_driver;
- +static struct uart_port *console_port;
- +static int console_baud = 115200;
- +static struct uart_cris_port serial_cris_ports[UART_NR] = {
- +{
- +#ifdef CONFIG_ETRAX_SERIAL_PORT0
- + .used = 1,
- + .irq = SER0_INTR_VECT,
- + .regi_ser = regi_ser0,
- + /*
- + * We initialize the dma stuff like this to get a compiler error
- + * if a CONFIG is missing
- + */
- + .regi_dmain =
- +# ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
- + regi_dma7,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT0_DMA1_IN)
- + regi_dma1,
- +# elif defined CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN
- + regi_NULL,
- +# endif
- +
- + .regi_dmaout =
- +# ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
- + regi_dma6,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT0_DMA7_OUT)
- + regi_dma7,
- +# else
- + regi_NULL,
- +# endif
- +
- +# ifdef CONFIG_ETRAX_RS485
- +# ifdef CONFIG_ETRAX_SERIAL_PORT0_TYPE_485HD
- + .port_type = TYPE_485HD,
- +# endif
- +# ifdef CONFIG_ETRAX_SERIAL_PORT0_TYPE_485FD
- + .port_type = TYPE_485FD,
- +# endif
- +# endif
- +#else
- + .regi_ser = regi_NULL,
- + .regi_dmain = regi_NULL,
- + .regi_dmaout = regi_NULL,
- +#endif
- + .write_ongoing = 0
- +}, /* ttyS0 */
- +{
- +#ifdef CONFIG_ETRAX_SERIAL_PORT1
- + .used = 1,
- + .irq = SER1_INTR_VECT,
- + .regi_ser = regi_ser1,
- + .regi_dmain =
- +# ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA5_IN
- + regi_dma5,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_IN)
- + regi_NULL,
- +# endif
- +
- + .regi_dmaout =
- +# ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA4_OUT
- + regi_dma4,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_OUT)
- + regi_NULL,
- +# endif
- +
- +# ifdef CONFIG_ETRAX_RS485
- +# ifdef CONFIG_ETRAX_SERIAL_PORT1_TYPE_485HD
- + .port_type = TYPE_485HD,
- +# endif
- +# ifdef CONFIG_ETRAX_SERIAL_PORT1_TYPE_485FD
- + .port_type = TYPE_485FD,
- +# endif
- +# endif
- +#else
- + .regi_ser = regi_NULL,
- + .regi_dmain = regi_NULL,
- + .regi_dmaout = regi_NULL,
- +#endif
- + .write_ongoing = 0
- +}, /* ttyS1 */
- +{
- +#ifdef CONFIG_ETRAX_SERIAL_PORT2
- + .used = 1,
- + .irq = SER2_INTR_VECT,
- + .regi_ser = regi_ser2,
- + .regi_dmain =
- +# ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
- + regi_dma3,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT2_DMA7_IN)
- + regi_dma7,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN)
- + regi_NULL,
- +# endif
- +
- + .regi_dmaout =
- +# ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
- + regi_dma2,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT2_DMA6_OUT)
- + regi_dma6,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT)
- + regi_NULL,
- +# endif
- +
- +# ifdef CONFIG_ETRAX_RS485
- +# ifdef CONFIG_ETRAX_SERIAL_PORT2_TYPE_485HD
- + .port_type = TYPE_485HD,
- +# endif
- +# ifdef CONFIG_ETRAX_SERIAL_PORT2_TYPE_485FD
- + .port_type = TYPE_485FD,
- +# endif
- +# endif
- +#else
- + .regi_ser = regi_NULL,
- + .regi_dmain = regi_NULL,
- + .regi_dmaout = regi_NULL,
- +#endif
- + .write_ongoing = 0
- +}, /* ttyS2 */
- +{
- +#ifdef CONFIG_ETRAX_SERIAL_PORT3
- + .used = 1,
- + .irq = SER3_INTR_VECT,
- + .regi_ser = regi_ser3,
- + .regi_dmain =
- +# ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA9_IN
- + regi_dma9,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT3_DMA4_IN)
- + regi_dma3,
- +# else
- + regi_NULL,
- +# endif
- +
- + .regi_dmaout =
- +# ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA8_OUT
- + regi_dma8,
- +# elif defined(CONFIG_ETRAX_SERIAL_PORT3_DMA2_OUT)
- + regi_dma2,
- +# else
- + regi_NULL,
- +# endif
- +# ifdef CONFIG_ETRAX_RS485
- +# ifdef CONFIG_ETRAX_SERIAL_PORT3_TYPE_485HD
- + .port_type = TYPE_485HD,
- +# endif
- +# ifdef CONFIG_ETRAX_SERIAL_PORT3_TYPE_485FD
- + .port_type = TYPE_485FD,
- +# endif
- +# endif
- +#else
- + .regi_ser = regi_NULL,
- + .regi_dmain = regi_NULL,
- + .regi_dmaout = regi_NULL,
- +#endif
- + .write_ongoing = 0
- +}, /* ttyS3 */
- +#if CONFIG_ETRAX_SERIAL_PORTS == 5
- +{
- +#ifdef CONFIG_ETRAX_SERIAL_PORT4
- + .used = 1,
- + .irq = SER4_INTR_VECT,
- + .regi_ser = regi_ser4,
- + .regi_dmain =
- +# ifdef CONFIG_ETRAX_SERIAL_PORT4_DMA9_IN
- + regi_dma9,
- +# else
- + regi_NULL,
- +# endif
- +
- + .regi_dmaout = regi_NULL,
- +# ifdef CONFIG_ETRAX_RS485
- +# ifdef CONFIG_ETRAX_SERIAL_PORT4_TYPE_485HD
- + .port_type = TYPE_485HD,
- +# endif
- +# ifdef CONFIG_ETRAX_SERIAL_PORT4_TYPE_485FD
- + .port_type = TYPE_485FD,
- +# endif
- +# endif
- +#else
- + .regi_ser = regi_NULL,
- + .regi_dmain = regi_NULL,
- + .regi_dmaout = regi_NULL,
- +#endif
- + .write_ongoing = 0
- +}, /* ttyS4 */
- +#endif
- +{
- +#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
- + .used = 1,
- +#endif
- + .regi_ser = regi_NULL,
- + .write_ongoing = 0
- +} /* Dummy console port */
- +
- +};
- +
- +/* Dummy pin used for unused CD, DSR, DTR and RI signals. */
- +static unsigned long io_dummy;
- +static struct crisv32_ioport dummy_port =
- +{
- + &io_dummy,
- + &io_dummy,
- + &io_dummy,
- + 32
- +};
- +static struct crisv32_iopin dummy_pin =
- +{
- + &dummy_port,
- + 0
- +};
- +
- +static int selected_console =
- +#if defined(CONFIG_ETRAX_DEBUG_PORT0)
- +0;
- +#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
- +1;
- +#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
- +2;
- +#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
- +3;
- +#elif defined(CONFIG_ETRAX_DEBUG_PORT4)
- +4;
- +#else /* CONFIG_ETRAX_DEBUG_PORT_NULL */
- +#if CONFIG_ETRAX_SERIAL_PORTS == 5
- +5;
- +#else
- +4;
- +#endif
- +#endif
- +
- +extern void reset_watchdog(void);
- +
- +static void serial_cris_stop_rx(struct uart_port *port);
- +
- +/*
- + * Interrupts are disabled on entering
- + */
- +#ifndef CONFIG_ETRAX_VCS_SIM
- +static void
- +cris_console_write(struct console *co, const char *s, unsigned int count)
- +{
- + struct uart_cris_port *up;
- + int i;
- + reg_ser_r_stat_din stat;
- + reg_ser_rw_tr_dma_en tr_dma_en, old;
- +
- + up = &serial_cris_ports[selected_console];
- +
- + /*
- + * This function isn't covered by the struct uart_ops, so we
- + * have to check manually that the port really is there,
- + * configured and live.
- + */
- + if (!up->regi_ser)
- + return;
- +
- + /* Switch to manual mode. */
- + tr_dma_en = old = REG_RD (ser, up->regi_ser, rw_tr_dma_en);
- + if (tr_dma_en.en == regk_ser_yes) {
- + tr_dma_en.en = regk_ser_no;
- + REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
- + }
- +
- + /* Send data. */
- + for (i = 0; i < count; i++) {
- + /* LF -> CRLF */
- + if (s[i] == '\n') {
- + do {
- + stat = REG_RD (ser, up->regi_ser, r_stat_din);
- + } while (!stat.tr_rdy);
- + REG_WR_INT (ser, up->regi_ser, rw_dout, '\r');
- + }
- + /* Wait until transmitter is ready and send. */
- + do {
- + stat = REG_RD (ser, up->regi_ser, r_stat_din);
- + } while (!stat.tr_rdy);
- + REG_WR_INT (ser, up->regi_ser, rw_dout, s[i]);
- +
- + /* Feed watchdog, because this may take looong time. */
- + reset_watchdog();
- + }
- +
- + /* Restore mode. */
- + if (tr_dma_en.en != old.en)
- + REG_WR(ser, up->regi_ser, rw_tr_dma_en, old);
- +}
- +#else
- +
- +extern void print_str( const char *str );
- +static char buffer[1024];
- +static char msg[] = "Debug: ";
- +static int buffer_pos = sizeof(msg) - 1;
- +
- +static void
- +cris_console_write(struct console *co, const char *buf, unsigned int len)
- +{
- + char* pos;
- + pos = memchr(buf, '\n', len);
- + if (pos) {
- + int l = ++pos - buf;
- + memcpy(buffer + buffer_pos, buf, l);
- + memcpy(buffer, msg, sizeof(msg) - 1);
- + buffer[buffer_pos + l] = '\0';
- + print_str(buffer);
- + buffer_pos = sizeof(msg) - 1;
- + if (pos - buf != len) {
- + memcpy(buffer + buffer_pos, pos, len - l);
- + buffer_pos += len - l;
- + }
- + } else {
- + memcpy(buffer + buffer_pos, buf, len);
- + buffer_pos += len;
- + }
- +}
- +#endif
- +
- +static void cris_serial_port_init(struct uart_port *port, int line);
- +static int __init
- +cris_console_setup(struct console *co, char *options)
- +{
- + struct uart_port *port;
- + int baud = 115200;
- + int bits = 8;
- + int parity = 'n';
- + int flow = 'n';
- +
- + if (co->index >= UART_NR)
- + co->index = 0;
- + if (options)
- + selected_console = co->index;
- + port = &serial_cris_ports[selected_console].port;
- + console_port = port;
- +
- + co->flags |= CON_CONSDEV;
- +
- + if (options)
- + uart_parse_options(options, &baud, &parity, &bits, &flow);
- + console_baud = baud;
- + cris_serial_port_init(port, selected_console);
- + co->index = port->line;
- + uart_set_options(port, co, baud, parity, bits, flow);
- +
- + return 0;
- +}
- +
- +static struct tty_driver*
- +cris_console_device(struct console* co, int *index)
- +{
- + struct uart_driver *p = co->data;
- + *index = selected_console;
- + return p->tty_driver;
- +}
- +
- +static struct console cris_console = {
- + .name = "ttyS",
- + .write = cris_console_write,
- + .device = cris_console_device,
- + .setup = cris_console_setup,
- + .flags = CON_PRINTBUFFER,
- + .index = -1,
- + .data = &serial_cris_driver,
- +};
- +
- +#define SERIAL_CRIS_CONSOLE &cris_console
- +
- +struct uart_driver serial_cris_driver = {
- + .owner = THIS_MODULE,
- + .driver_name = "serial",
- + .dev_name = "ttyS",
- + .major = TTY_MAJOR,
- + .minor = 64,
- + .nr = UART_NR,
- + .cons = SERIAL_CRIS_CONSOLE,
- +};
- +
- +static int inline crisv32_serial_get_rts(struct uart_cris_port *up)
- +{
- + reg_scope_instances regi_ser = up->regi_ser;
- + /*
- + * Return what the user has controlled rts to or
- + * what the pin is? (if auto_rts is used it differs during tx)
- + */
- + reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
- + return !(rstat.rts_n == regk_ser_active);
- +}
- +
- +/*
- + * A set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
- + * 0=0V , 1=3.3V
- + */
- +static inline void crisv32_serial_set_rts(struct uart_cris_port *up, int set, int force)
- +{
- + reg_scope_instances regi_ser = up->regi_ser;
- +
- +#ifdef CONFIG_ETRAX_RS485
- + /* Never toggle RTS if port is in 485 mode. If port is in 485FD mode we
- + * do not want to send with the reciever and for 485HD mode auto_rts
- + * take care of the RTS for us.
- + */
- + if (force || !up->rs485.enabled) {
- +#else
- + {
- +#endif
- + unsigned long flags;
- + reg_ser_rw_rec_ctrl rec_ctrl;
- +
- + local_irq_save(flags);
- + rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
- +
- + if (set)
- + rec_ctrl.rts_n = regk_ser_active;
- + else
- + rec_ctrl.rts_n = regk_ser_inactive;
- + REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
- + local_irq_restore(flags);
- + }
- +}
- +
- +/* Input */
- +static int inline crisv32_serial_get_cts(struct uart_cris_port *up)
- +{
- + reg_scope_instances regi_ser = up->regi_ser;
- + reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
- + return (rstat.cts_n == regk_ser_active);
- +}
- +
- +/*
- + * Send a single character for XON/XOFF purposes. We do it in this separate
- + * function instead of the alternative support port.x_char, in the ...start_tx
- + * function, so we don't mix up this case with possibly enabling transmission
- + * of queued-up data (in case that's disabled after *receiving* an XOFF or
- + * negative CTS). This function is used for both DMA and non-DMA case; see HW
- + * docs specifically blessing sending characters manually when DMA for
- + * transmission is enabled and running. We may be asked to transmit despite
- + * the transmitter being disabled by a ..._stop_tx call so we need to enable
- + * it temporarily but restore the state afterwards.
- + *
- + * Beware: I'm not sure how the RS-485 stuff is supposed to work. Using
- + * XON/XOFF seems problematic if there are several controllers, but if it's
- + * actually RS-422 (multi-drop; one sender and multiple receivers), it might
- + * Just Work, so don't bail out just because it looks a little suspicious.
- + */
- +
- +void serial_cris_send_xchar(struct uart_port *port, char ch)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + reg_ser_rw_dout dout = { .data = ch };
- + reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
- + reg_ser_r_stat_din rstat;
- + reg_ser_rw_tr_ctrl prev_tr_ctrl, tr_ctrl;
- + reg_scope_instances regi_ser = up->regi_ser;
- + unsigned long flags;
- +
- + /*
- + * Wait for tr_rdy in case a character is already being output. Make
- + * sure we have integrity between the register reads and the writes
- + * below, but don't busy-wait with interrupts off and the port lock
- + * taken.
- + */
- + spin_lock_irqsave(&port->lock, flags);
- + do {
- + spin_unlock_irqrestore(&port->lock, flags);
- + spin_lock_irqsave(&port->lock, flags);
- + prev_tr_ctrl = tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
- + rstat = REG_RD(ser, regi_ser, r_stat_din);
- + } while (!rstat.tr_rdy);
- +
- + /*
- + * Ack an interrupt if one was just issued for the previous character
- + * that was output. This is required for non-DMA as the interrupt is
- + * used as the only indicator that the transmitter is ready and it
- + * isn't while this x_char is being transmitted.
- + */
- + REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
- +
- + /* Enable the transmitter in case it was disabled. */
- + tr_ctrl.stop = 0;
- + REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
- +
- + /*
- + * Finally, send the blessed character; nothing should stop it now,
- + * except for an xoff-detected state, which we'll handle below.
- + */
- + REG_WR(ser, regi_ser, rw_dout, dout);
- + up->port.icount.tx++;
- +
- + /* There might be an xoff state to clear. */
- + rstat = REG_RD(ser, up->regi_ser, r_stat_din);
- +
- + /*
- + * Clear any xoff state that *may* have been there to
- + * inhibit transmission of the character.
- + */
- + if (rstat.xoff_detect) {
- + reg_ser_rw_xoff_clr xoff_clr = { .clr = 1 };
- + reg_ser_rw_tr_dma_en tr_dma_en;
- + REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
- + tr_dma_en = REG_RD(ser, regi_ser, rw_tr_dma_en);
- +
- + /*
- + * If we had an xoff state but cleared it, instead sneak in a
- + * disabled state for the transmitter, after the character we
- + * sent. Thus we keep the port disabled, just as if the xoff
- + * state was still in effect (or actually, as if stop_tx had
- + * been called, as we stop DMA too).
- + */
- + prev_tr_ctrl.stop = 1;
- +
- + tr_dma_en.en = 0;
- + REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
- + }
- +
- + /* Restore "previous" enabled/disabled state of the transmitter. */
- + REG_WR(ser, regi_ser, rw_tr_ctrl, prev_tr_ctrl);
- +
- + spin_unlock_irqrestore(&port->lock, flags);
- +}
- +
- +static void transmit_chars_dma(struct uart_cris_port *up);
- +
- +/*
- + * Do not spin_lock_irqsave or disable interrupts by other means here; it's
- + * already done by the caller.
- + */
- +
- +static void serial_cris_start_tx(struct uart_port *port)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + reg_scope_instances regi_ser = up->regi_ser;
- + reg_ser_rw_tr_ctrl tr_ctrl;
- +
- + /* we have already done below if a write is ongoing */
- + if (!up->regi_dmaout && up->write_ongoing)
- + return;
- +
- +#ifdef CONFIG_ETRAX_RS485
- + if (up->rs485.enabled)
- + {
- + /* If we are in RS-485 mode, we need to toggle RTS and disable
- + * the receiver before initiating a DMA transfer
- + */
- +
- + if (up->rs485.delay_rts_before_send > 0) {
- + reg_ser_rw_tr_ctrl tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
- + tr_ctrl.auto_rts = regk_ser_no;
- + REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
- + crisv32_serial_set_rts(up, up->rs485.rts_on_send, 1);
- + msleep(up->rs485.delay_rts_before_send);
- + tr_ctrl.auto_rts = regk_ser_yes;
- + REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
- + crisv32_serial_set_rts(up, !up->rs485.rts_on_send, 1);
- + }
- + }
- +#endif
- +
- + tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
- + tr_ctrl.stop = regk_ser_no;
- + REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
- + if (!up->regi_dmaout) {
- + reg_ser_rw_intr_mask intr_mask =
- + REG_RD(ser, regi_ser, rw_intr_mask);
- + intr_mask.tr_rdy = regk_ser_yes;
- + REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
- + up->write_ongoing = 1;
- + } else {
- + /*
- + * We're called possibly to re-enable transmission after it
- + * has been disabled. If so, DMA needs to be re-enabled.
- + */
- + reg_ser_rw_tr_dma_en tr_dma_en = { .en = 1 };
- + REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
- + transmit_chars_dma(up);
- + }
- +}
- +
- +/*
- + * This function handles both the DMA and non-DMA case by ordering the
- + * transmitter to stop of after the current character. We don't need to wait
- + * for any such character to be completely transmitted; we do that where it
- + * matters, like in serial_cris_set_termios. Don't busy-wait here; see
- + * Documentation/serial/driver: this function is called within
- + * spin_lock_irq{,save} and thus separate ones would be disastrous (when SMP).
- + * There's no documented need to set the txd pin to any particular value;
- + * break setting is controlled solely by serial_cris_break_ctl.
- + */
- +
- +static void serial_cris_stop_tx(struct uart_port *port)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + reg_scope_instances regi_ser = up->regi_ser;
- + reg_ser_rw_tr_ctrl tr_ctrl;
- + reg_ser_rw_intr_mask intr_mask;
- + reg_ser_rw_tr_dma_en tr_dma_en = {0};
- + reg_ser_rw_xoff_clr xoff_clr = {0};
- +
- + /*
- + * For the non-DMA case, we'd get a tr_rdy interrupt that we're not
- + * interested in as we're not transmitting any characters. For the
- + * DMA case, that interrupt is already turned off, but no reason to
- + * waste code on conditionals here.
- + */
- + intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
- + intr_mask.tr_rdy = regk_ser_no;
- + REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
- +
- + tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
- + tr_ctrl.stop = 1;
- + REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
- +
- + /*
- + * Always clear possible hardware xoff-detected state here, no need to
- + * unnecessary consider mctrl settings and when they change. We clear
- + * it here rather than in start_tx: both functions are called as the
- + * effect of XOFF processing, but start_tx is also called when upper
- + * levels tell the driver that there are more characters to send, so
- + * avoid adding code there.
- + */
- + xoff_clr.clr = 1;
- + REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
- +
- + /*
- + * Disable transmitter DMA, so that if we're in XON/XOFF, we can send
- + * those single characters without also giving go-ahead for queued up
- + * DMA data.
- + */
- + tr_dma_en.en = 0;
- + REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
- +}
- +
- +static void serial_cris_stop_rx(struct uart_port *port)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + reg_scope_instances regi_ser = up->regi_ser;
- + reg_ser_rw_rec_ctrl rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
- +
- + rec_ctrl.en = regk_ser_no;
- + REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
- +}
- +
- +static void serial_cris_enable_ms(struct uart_port *port)
- +{
- +}
- +
- +static void check_modem_status(struct uart_cris_port *up)
- +{
- +}
- +
- +static unsigned int serial_cris_tx_empty(struct uart_port *port)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + unsigned long flags;
- + unsigned int ret;
- + reg_ser_r_stat_din rstat = {0};
- +
- + spin_lock_irqsave(&up->port.lock, flags);
- + if (up->regi_dmaout) {
- + /*
- + * For DMA, before looking at r_stat, we need to check that we
- + * either haven't actually started or that end-of-list is
- + * reached, else a tr_empty indication is just an internal
- + * state. The caller qualifies, if needed, that the
- + * port->info.xmit buffer is empty, so we don't need to
- + * check that.
- + */
- + reg_dma_rw_stat status = REG_RD(dma, up->regi_dmaout, rw_stat);
- +
- + if (!up->tx_started) {
- + ret = 1;
- + goto done;
- + }
- +
- + if (status.list_state != regk_dma_data_at_eol) {
- + ret = 0;
- + goto done;
- + }
- + }
- +
- + rstat = REG_RD(ser, up->regi_ser, r_stat_din);
- + ret = rstat.tr_empty ? TIOCSER_TEMT : 0;
- +
- + done:
- + spin_unlock_irqrestore(&up->port.lock, flags);
- + return ret;
- +}
- +static unsigned int serial_cris_get_mctrl(struct uart_port *port)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + unsigned int ret;
- +
- + ret = 0;
- + if (crisv32_serial_get_rts(up))
- + ret |= TIOCM_RTS;
- + /* DTR is active low */
- + if (!crisv32_io_rd(&up->dtr_pin))
- + ret |= TIOCM_DTR;
- + /* CD is active low */
- + if (!crisv32_io_rd(&up->cd_pin))
- + ret |= TIOCM_CD;
- + /* RI is active low */
- + if (!crisv32_io_rd(&up->ri_pin))
- + ret |= TIOCM_RI;
- + /* DSR is active low */
- + if (!crisv32_io_rd(&up->dsr_pin))
- + ret |= TIOCM_DSR;
- + if (crisv32_serial_get_cts(up))
- + ret |= TIOCM_CTS;
- + return ret;
- +}
- +
- +static void serial_cris_set_mctrl(struct uart_port *port, unsigned int mctrl)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- +
- + crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0, 0);
- + /* DTR is active low */
- + crisv32_io_set(&up->dtr_pin, mctrl & TIOCM_DTR ? 0 : 1);
- + /* RI is active low */
- + crisv32_io_set(&up->ri_pin, mctrl & TIOCM_RNG ? 0 : 1);
- + /* CD is active low */
- + crisv32_io_set(&up->cd_pin, mctrl & TIOCM_CD ? 0 : 1);
- +}
- +
- +static void serial_cris_break_ctl(struct uart_port *port, int break_state)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + unsigned long flags;
- + reg_ser_rw_tr_ctrl tr_ctrl;
- + reg_ser_rw_tr_dma_en tr_dma_en;
- + reg_ser_rw_intr_mask intr_mask;
- +
- + spin_lock_irqsave(&up->port.lock, flags);
- + tr_ctrl = REG_RD(ser, up->regi_ser, rw_tr_ctrl);
- + tr_dma_en = REG_RD(ser, up->regi_ser, rw_tr_dma_en);
- + intr_mask = REG_RD(ser, up->regi_ser, rw_intr_mask);
- +
- + if (break_state != 0) { /* Send break */
- + /*
- + * We need to disable DMA (if used) or tr_rdy interrupts if no
- + * DMA. No need to make this conditional on use of DMA;
- + * disabling will be a no-op for the other mode.
- + */
- + intr_mask.tr_rdy = regk_ser_no;
- + tr_dma_en.en = 0;
- +
- + /*
- + * Stop transmission and set the txd pin to 0 after the
- + * current character. The txd setting will take effect after
- + * any current transmission has completed.
- + */
- + tr_ctrl.stop = 1;
- + tr_ctrl.txd = 0;
- + } else {
- + /* Re-enable either transmit DMA or the serial interrupt. */
- + if (up->regi_dmaout)
- + tr_dma_en.en = 1;
- + else
- + intr_mask.tr_rdy = regk_ser_yes;
- +
- +
- + tr_ctrl.stop = 0;
- + tr_ctrl.txd = 1;
- + }
- + REG_WR(ser, up->regi_ser, rw_tr_ctrl, tr_ctrl);
- + REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
- + REG_WR(ser, up->regi_ser, rw_intr_mask, intr_mask);
- +
- + spin_unlock_irqrestore(&up->port.lock, flags);
- +}
- +
- +/*
- + * The output DMA channel is free - use it to send as many chars as
- + * possible.
- + */
- +
- +static void
- +transmit_chars_dma(struct uart_cris_port *up)
- +{
- + struct dma_descr_data *descr, *pending_descr, *dmapos;
- + struct dma_descr_data *last_tx_descr;
- + struct circ_buf *xmit = &up->port.state->xmit;
- + unsigned int sentl = 0;
- + reg_dma_rw_ack_intr ack_intr = { .data = regk_dma_yes };
- + reg_dma_rw_stat status;
- + reg_scope_instances regi_dmaout = up->regi_dmaout;
- + unsigned int chars_in_q;
- + unsigned int chars_to_send;
- +
- + /* Acknowledge dma data descriptor irq, if there was one. */
- + REG_WR(dma, regi_dmaout, rw_ack_intr, ack_intr);
- +
- + /*
- + * First get the amount of bytes sent during the last DMA transfer,
- + * and update xmit accordingly.
- + */
- + status = REG_RD(dma, regi_dmaout, rw_stat);
- + if (status.list_state == regk_dma_data_at_eol || !up->tx_started)
- + dmapos = phys_to_virt((int)up->last_tx_descr->next);
- + else
- + dmapos = phys_to_virt(REG_RD_INT(dma, regi_dmaout, rw_data));
- +
- + pending_descr = up->first_tx_descr;
- + while (pending_descr != dmapos) {
- + sentl += pending_descr->after - pending_descr->buf;
- + pending_descr->after = pending_descr->buf = NULL;
- + pending_descr = phys_to_virt((int)pending_descr->next);
- + }
- +
- + up->first_tx_descr = pending_descr;
- + last_tx_descr = up->last_tx_descr;
- +
- + /* Update stats. */
- + up->port.icount.tx += sentl;
- +
- + up->tx_pending_chars -= sentl;
- +
- + /* Update xmit buffer. */
- + xmit->tail = (xmit->tail + sentl) & (UART_XMIT_SIZE - 1);
- +
- + /*
- + * Find out the largest amount of consecutive bytes we want to send
- + * now.
- + */
- + chars_in_q = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
- +
- + if (chars_in_q == 0)
- + /* Tell upper layers that we're now idle. */
- + goto done;
- +
- + /* Some of those characters are actually pending output. */
- + chars_to_send = chars_in_q - up->tx_pending_chars;
- +
- + /*
- + * Clamp the new number of pending chars to the advertised
- + * one.
- + */
- + if (chars_to_send + up->tx_pending_chars > up->port.fifosize)
- + chars_to_send = up->port.fifosize - up->tx_pending_chars;
- +
- + /* If we don't want to send any, we're done. */
- + if (chars_to_send == 0)
- + goto done;
- +
- + descr = phys_to_virt((int)last_tx_descr->next);
- +
- + /*
- + * We can't send anything if we could make the condition in
- + * the while-loop above (reaping finished descriptors) be met
- + * immediately before the first iteration. However, don't
- + * mistake the full state for the empty state.
- + */
- + if ((descr == up->first_tx_descr && up->tx_pending_chars != 0)
- + || descr->next == up->first_tx_descr)
- + goto done;
- +
- + /* Set up the descriptor for output. */
- + descr->buf = (void*)virt_to_phys(xmit->buf + xmit->tail
- + + up->tx_pending_chars);
- + descr->after = descr->buf + chars_to_send;
- + descr->eol = 1;
- + descr->out_eop = 0;
- + descr->intr = 1;
- + descr->wait = 0;
- + descr->in_eop = 0;
- + descr->md = 0;
- + /*
- + * Make sure GCC doesn't move this eol clear before the eol set
- + * above.
- + */
- + barrier();
- + last_tx_descr->eol = 0;
- +
- + up->last_tx_descr = descr;
- + up->tx_pending_chars += chars_to_send;
- +
- + if (!up->tx_started) {
- + up->tx_started = 1;
- + up->tr_context_descr.next = 0;
- + up->tr_context_descr.saved_data
- + = (dma_descr_data*)virt_to_phys(descr);
- + up->tr_context_descr.saved_data_buf = descr->buf;
- + DMA_START_CONTEXT(regi_dmaout,
- + virt_to_phys(&up->tr_context_descr));
- + } else
- + DMA_CONTINUE_DATA(regi_dmaout);
- +
- + /* DMA is now running (hopefully). */
- +
- + done:
- + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- + uart_write_wakeup(&up->port);
- +}
- +
- +static void
- +transmit_chars_no_dma(struct uart_cris_port *up)
- +{
- + int max_count;
- + struct circ_buf *xmit = &up->port.state->xmit;
- +
- + reg_scope_instances regi_ser = up->regi_ser;
- + reg_ser_r_stat_din rstat;
- + reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
- +
- + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- + /* No more to send, so disable the interrupt. */
- + reg_ser_rw_intr_mask intr_mask;
- + intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
- + intr_mask.tr_rdy = 0;
- + intr_mask.tr_empty = 0;
- + REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
- + up->write_ongoing=0;
- + return;
- + }
- +
- + /* If the serport is fast, we send up to max_count bytes before
- + exiting the loop. */
- + max_count = 64;
- + do {
- + reg_ser_rw_dout dout = { .data = xmit->buf[xmit->tail] };
- + REG_WR(ser, regi_ser, rw_dout, dout);
- + REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
- + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
- + up->port.icount.tx++;
- + if (xmit->head == xmit->tail)
- + break;
- + rstat = REG_RD(ser, regi_ser, r_stat_din);
- + } while ((--max_count > 0) && rstat.tr_rdy);
- +
- + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- + uart_write_wakeup(&up->port);
- +} /* transmit_chars_no_dma */
- +
- +static struct etrax_recv_buffer *
- +alloc_recv_buffer(unsigned int size)
- +{
- + struct etrax_recv_buffer *buffer;
- +
- + if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
- + panic("%s: Could not allocate %d bytes buffer\n",
- + __FUNCTION__, size);
- +
- + buffer->next = NULL;
- + buffer->length = 0;
- + buffer->error = TTY_NORMAL;
- +
- + return buffer;
- +}
- +
- +static void
- +append_recv_buffer(struct uart_cris_port *up,
- + struct etrax_recv_buffer *buffer)
- +{
- + unsigned long flags;
- +
- + local_irq_save(flags);
- +
- + if (!up->first_recv_buffer)
- + up->first_recv_buffer = buffer;
- + else
- + up->last_recv_buffer->next = buffer;
- +
- + up->last_recv_buffer = buffer;
- +
- + up->recv_cnt += buffer->length;
- + if (up->recv_cnt > up->max_recv_cnt)
- + up->max_recv_cnt = up->recv_cnt;
- +
- + local_irq_restore(flags);
- +}
- +
- +static int
- +add_char_and_flag(struct uart_cris_port *up, unsigned char data,
- + unsigned char flag)
- +{
- + struct etrax_recv_buffer *buffer;
- +
- + buffer = alloc_recv_buffer(4);
- + buffer->length = 1;
- + buffer->error = flag;
- + buffer->buffer[0] = data;
- +
- + append_recv_buffer(up, buffer);
- +
- + up->port.icount.rx++;
- +
- + return 1;
- +}
- +
- +static void
- +flush_to_flip_buffer(struct uart_cris_port *up)
- +{
- + struct etrax_recv_buffer *buffer;
- +
- + if (!up->first_recv_buffer)
- + return;
- +
- + while ((buffer = up->first_recv_buffer)) {
- + unsigned int count = (unsigned int)
- + tty_insert_flip_string(&up->port.state->port,
- + buffer->buffer,
- + buffer->length);
- +
- + up->recv_cnt -= count;
- +
- + if (count == buffer->length) {
- + up->first_recv_buffer = buffer->next;
- + kfree(buffer);
- + } else {
- + buffer->length -= count;
- + memmove(buffer->buffer, buffer->buffer + count,
- + buffer->length);
- + buffer->error = TTY_NORMAL;
- + }
- + }
- +
- + if (!up->first_recv_buffer)
- + up->last_recv_buffer = NULL;
- +
- + /* This call includes a check for low-latency. */
- + tty_flip_buffer_push(&up->port.state->port);
- +}
- +
- +static unsigned int
- +handle_descr_data(struct uart_cris_port *up, struct dma_descr_data *descr,
- + unsigned int recvl)
- +{
- + struct etrax_recv_buffer *buffer
- + = phys_to_virt((unsigned long)descr->buf) - sizeof *buffer;
- +
- + if (up->recv_cnt + recvl > 65536) {
- + printk(KERN_ERR "Too much pending incoming data on %s!"
- + " Dropping %u bytes.\n", up->port.state->port.tty->name,
- + recvl);
- + return 0;
- + }
- +
- + buffer->length = recvl;
- +
- + append_recv_buffer(up, buffer);
- +
- + flush_to_flip_buffer(up);
- +
- + buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
- + descr->buf = (void*)virt_to_phys(buffer->buffer);
- + descr->after = descr->buf + SERIAL_DESCR_BUF_SIZE;
- +
- + return recvl;
- +}
- +
- +static unsigned int
- +handle_all_descr_data(struct uart_cris_port *up)
- +{
- + struct dma_descr_data *descr
- + = &up->rec_descr[(up->cur_rec_descr - 1)
- + % SERIAL_RECV_DESCRIPTORS];
- + struct dma_descr_data *prev_descr;
- + unsigned int recvl;
- + unsigned int ret = 0;
- + reg_scope_instances regi_dmain = up->regi_dmain;
- +
- + while (1) {
- + prev_descr = descr;
- + descr = &up->rec_descr[up->cur_rec_descr];
- +
- + if (descr == phys_to_virt(REG_RD(dma, regi_dmain, rw_data)))
- + break;
- +
- + if (++up->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
- + up->cur_rec_descr = 0;
- +
- + /* Find out how many bytes were read. */
- + recvl = descr->after - descr->buf;
- +
- + /* Update stats. */
- + up->port.icount.rx += recvl;
- +
- + ret += handle_descr_data(up, descr, recvl);
- + descr->eol = 1;
- + /*
- + * Make sure GCC doesn't move this eol clear before the
- + * eol set above.
- + */
- + barrier();
- + prev_descr->eol = 0;
- + flush_dma_descr(descr,1); // Cache bug workaround
- + flush_dma_descr(prev_descr,0); // Cache bug workaround
- + }
- +
- + return ret;
- +}
- +
- +static void
- +receive_chars_dma(struct uart_cris_port *up)
- +{
- + reg_ser_r_stat_din rstat;
- + reg_dma_rw_ack_intr ack_intr = {0};
- +
- + /* Acknowledge both dma_descr and dma_eop irq. */
- + ack_intr.data = 1;
- + ack_intr.in_eop = 1;
- + REG_WR(dma, up->regi_dmain, rw_ack_intr, ack_intr);
- +
- + handle_all_descr_data(up);
- +
- + /* Read the status register to detect errors. */
- + rstat = REG_RD(ser, up->regi_ser, r_stat_din);
- +
- + if (rstat.framing_err | rstat.par_err | rstat.orun) {
- + /*
- + * If we got an error, we must reset it by reading the
- + * rs_stat_din register and put the data in buffer manually.
- + */
- + reg_ser_rs_stat_din stat_din;
- + stat_din = REG_RD(ser, up->regi_ser, rs_stat_din);
- +
- + if (stat_din.par_err)
- + add_char_and_flag(up, stat_din.data, TTY_PARITY);
- + else if (stat_din.orun)
- + add_char_and_flag(up, stat_din.data, TTY_OVERRUN);
- + else if (stat_din.framing_err)
- + add_char_and_flag(up, stat_din.data, TTY_FRAME);
- + }
- +
- + /* Restart the receiving DMA, in case it got stuck on an EOL. */
- + DMA_CONTINUE_DATA(up->regi_dmain);
- +}
- +
- +void receive_chars_no_dma(struct uart_cris_port *up)
- +{
- + reg_ser_rs_stat_din stat_din;
- + reg_ser_r_stat_din rstat;
- + struct uart_icount *icount;
- + int max_count = 16;
- + char flag;
- + reg_ser_rw_ack_intr ack_intr = { 0 };
- +
- + rstat = REG_RD(ser, up->regi_ser, r_stat_din);
- + up->last_rx_active_usec = GET_JIFFIES_USEC();
- + up->last_rx_active = jiffies;
- + icount = &up->port.icount;
- +
- + do {
- + stat_din = REG_RD(ser, up->regi_ser, rs_stat_din);
- +
- + flag = TTY_NORMAL;
- + ack_intr.dav = 1;
- + REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr);
- + icount->rx++;
- +
- + if (stat_din.framing_err | stat_din.par_err | stat_din.orun) {
- + if (stat_din.data == 0x00 &&
- + stat_din.framing_err) {
- + /* Most likely a break. */
- + flag = TTY_BREAK;
- + icount->brk++;
- + } else if (stat_din.par_err) {
- + flag = TTY_PARITY;
- + icount->parity++;
- + } else if (stat_din.orun) {
- + flag = TTY_OVERRUN;
- + icount->overrun++;
- + } else if (stat_din.framing_err) {
- + flag = TTY_FRAME;
- + icount->frame++;
- + }
- + }
- +
- + /*
- + * If this becomes important, we probably *could* handle this
- + * gracefully by keeping track of the unhandled character.
- + */
- + if (!tty_insert_flip_char(&up->port.state->port, stat_din.data, flag))
- + panic("%s: No tty buffer space", __FUNCTION__);
- + rstat = REG_RD(ser, up->regi_ser, r_stat_din);
- + } while (rstat.dav && (max_count-- > 0));
- + spin_unlock(&up->port.lock);
- + tty_flip_buffer_push(&up->port.state->port);
- + spin_lock(&up->port.lock);
- +} /* receive_chars_no_dma */
- +
- +/*
- + * DMA output channel interrupt handler.
- + * this interrupt is called from DMA2(ser2), DMA8(ser3), DMA6(ser0) or
- + * DMA4(ser1) when they have finished a descriptor with the intr flag set.
- + */
- +static irqreturn_t dma_tr_interrupt(int irq, void *dev_id)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)dev_id;
- + reg_dma_r_masked_intr masked_intr;
- + reg_scope_instances regi_dmaout;
- + int handled = 0;
- +
- + spin_lock(&up->port.lock);
- + regi_dmaout = up->regi_dmaout;
- + if (!regi_dmaout) {
- + spin_unlock(&up->port.lock);
- + return IRQ_NONE;
- + }
- +
- + /*
- + * Check for dma_descr (don't need to check for dma_eop in
- + * output DMA for serial).
- + */
- + masked_intr = REG_RD(dma, regi_dmaout, r_masked_intr);
- +
- + if (masked_intr.data) {
- + /* We can send a new dma bunch. make it so. */
- +
- + /*
- + * Read jiffies_usec first.
- + * We want this time to be as late as possible.
- + */
- + up->last_tx_active_usec = GET_JIFFIES_USEC();
- + up->last_tx_active = jiffies;
- + transmit_chars_dma(up);
- + handled = 1;
- + }
- + check_modem_status(up);
- + spin_unlock(&up->port.lock);
- + return IRQ_RETVAL(handled);
- +}
- +
- +/* DMA input channel interrupt handler. */
- +
- +static irqreturn_t
- +dma_rec_interrupt(int irq, void *dev_id)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)dev_id;
- + reg_dma_r_masked_intr masked_intr;
- + reg_scope_instances regi_dmain;
- + int handled = 0;
- +
- + spin_lock(&up->port.lock);
- + regi_dmain = up->regi_dmain;
- + if (!regi_dmain) {
- + spin_unlock(&up->port.lock);
- + return IRQ_NONE;
- + }
- +
- + /* Check for both dma_eop and dma_descr for the input dma channel. */
- + masked_intr = REG_RD(dma, regi_dmain, r_masked_intr);
- + if (masked_intr.data || masked_intr.in_eop) {
- + /* We have received something. */
- + receive_chars_dma(up);
- + handled = 1;
- + }
- + check_modem_status(up);
- + spin_unlock(&up->port.lock);
- + return IRQ_RETVAL(handled);
- +}
- +
- +/* "Normal" serial port interrupt handler - both rx and tx. */
- +
- +static irqreturn_t
- +ser_interrupt(int irq, void *dev_id)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)dev_id;
- + reg_scope_instances regi_ser;
- + int handled = 0;
- +
- + spin_lock(&up->port.lock);
- + if (up->regi_dmain && up->regi_dmaout) {
- + spin_unlock(&up->port.lock);
- + return IRQ_NONE;
- + }
- +
- + regi_ser = up->regi_ser;
- +
- + if (regi_ser) {
- + reg_ser_r_masked_intr masked_intr;
- + masked_intr = REG_RD(ser, regi_ser, r_masked_intr);
- + /*
- + * Check what interrupts are active before taking
- + * actions. If DMA is used the interrupt shouldn't
- + * be enabled.
- + */
- + if (masked_intr.dav) {
- + receive_chars_no_dma(up);
- + handled = 1;
- + }
- + check_modem_status(up);
- +
- + if (masked_intr.tr_rdy) {
- + transmit_chars_no_dma(up);
- + handled = 1;
- + }
- + }
- + spin_unlock(&up->port.lock);
- + return IRQ_RETVAL(handled);
- +} /* ser_interrupt */
- +
- +static int start_recv_dma(struct uart_cris_port *up)
- +{
- + struct dma_descr_data *descr = up->rec_descr;
- + struct etrax_recv_buffer *buffer;
- + int i;
- +
- + /* Set up the receiving descriptors. */
- + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
- + buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
- + descr[i].next = (void*)virt_to_phys(&descr[i+1]);
- + descr[i].buf = (void*)virt_to_phys(buffer->buffer);
- + descr[i].after = descr[i].buf + SERIAL_DESCR_BUF_SIZE;
- + descr[i].eol = 0;
- + descr[i].out_eop = 0;
- + descr[i].intr = 1;
- + descr[i].wait = 0;
- + descr[i].in_eop = 0;
- + descr[i].md = 0;
- +
- + }
- +
- + /* Link the last descriptor to the first. */
- + descr[i-1].next = (void*)virt_to_phys(&descr[0]);
- +
- + /* And mark it as end of list. */
- + descr[i-1].eol = 1;
- +
- + /* Start with the first descriptor in the list. */
- + up->cur_rec_descr = 0;
- + up->rec_context_descr.next = 0;
- + up->rec_context_descr.saved_data
- + = (dma_descr_data *)virt_to_phys(&descr[up->cur_rec_descr]);
- + up->rec_context_descr.saved_data_buf = descr[up->cur_rec_descr].buf;
- +
- + /* Start the DMA. */
- + DMA_START_CONTEXT(up->regi_dmain,
- + virt_to_phys(&up->rec_context_descr));
- +
- + /* Input DMA should be running now. */
- + return 1;
- +}
- +
- +#ifdef CONFIG_CONSOLE_POLL
- +/*
- + * Console polling routines for writing and reading from the uart while
- + * in an interrupt or debug context.
- + */
- +
- +static int serial_artpec_get_poll_char(struct uart_port *port)
- +{
- + reg_ser_rs_stat_din stat;
- + reg_ser_rw_ack_intr ack_intr = { 0 };
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- +
- + do {
- + stat = REG_RD(ser, up->regi_ser, rs_stat_din);
- + } while (!stat.dav);
- +
- + /* Ack the data_avail interrupt. */
- + ack_intr.dav = 1;
- + REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr);
- +
- + return stat.data;
- +}
- +
- +static void serial_artpec_put_poll_char(struct uart_port *port,
- + unsigned char c)
- +{
- + reg_ser_r_stat_din stat;
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- +
- + do {
- + stat = REG_RD (ser, up->regi_ser, r_stat_din);
- + } while (!stat.tr_rdy);
- + REG_WR_INT (ser, up->regi_ser, rw_dout, c);
- +}
- +#endif /* CONFIG_CONSOLE_POLL */
- +
- +static void start_receive(struct uart_cris_port *up)
- +{
- + reg_scope_instances regi_dmain = up->regi_dmain;
- + if (regi_dmain) {
- + start_recv_dma(up);
- + }
- +}
- +
- +
- +static void start_transmitter(struct uart_cris_port *up)
- +{
- + int i;
- + reg_scope_instances regi_dmaout = up->regi_dmaout;
- + if (regi_dmaout) {
- + for (i = 0; i < SERIAL_TX_DESCRIPTORS; i++) {
- + memset(&up->tr_descr[i], 0, sizeof(up->tr_descr[i]));
- + up->tr_descr[i].eol = 1;
- + up->tr_descr[i].intr = 1;
- + up->tr_descr[i].next = (dma_descr_data *)
- + virt_to_phys(&up->tr_descr[i+1]);
- + }
- + up->tr_descr[i-1].next = (dma_descr_data *)
- + virt_to_phys(&up->tr_descr[0]);
- + up->first_tx_descr = &up->tr_descr[0];
- +
- + /*
- + * We'll be counting up to up->last_tx_descr->next from
- + * up->first_tx_descr when starting DMA, so we should make
- + * them the same for the very first round. If instead we'd
- + * set last_tx_descr = first_tx_descr, we'd rely on
- + * accidentally working code and data as we'd take a pass over
- + * the first, unused, descriptor.
- + */
- + up->last_tx_descr = &up->tr_descr[i-1];
- + up->tx_started = 0;
- + up->tx_pending_chars = 0;
- + }
- +}
- +
- +static int serial_cris_startup(struct uart_port *port)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + unsigned long flags;
- + reg_ser_rw_intr_mask ser_intr_mask = {0};
- + reg_dma_rw_intr_mask dmain_intr_mask = {0};
- + reg_dma_rw_intr_mask dmaout_intr_mask = {0};
- + reg_dma_rw_cfg cfg = {.en = 1};
- + reg_scope_instances regi_dma;
- +
- + /* We dont disable interrupts here because request_irq should
- + not be called with ints disabled. */
- + spin_lock(&up->port.lock);
- +
- + dmain_intr_mask.data = dmain_intr_mask.in_eop = regk_dma_yes;
- + dmaout_intr_mask.data = regk_dma_yes;
- + if (!up->regi_dmain)
- + ser_intr_mask.dav = regk_ser_yes;
- +
- + if (port->line == 0) {
- + if (request_irq(SER0_INTR_VECT, ser_interrupt,
- + IRQF_DISABLED, "ser0",
- + &serial_cris_ports[0]))
- + panic("irq ser0");
- + /* Port ser0 can use dma6 for tx and dma7 for rx. */
- +#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
- + if (request_irq(DMA6_INTR_VECT, dma_tr_interrupt,
- + IRQF_DISABLED, "serial 0 dma tr",
- + &serial_cris_ports[0]))
- + panic("irq ser0txdma");
- + crisv32_request_dma(6, "ser0", DMA_PANIC_ON_ERROR, 0,
- + dma_ser0);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
- + if (request_irq(DMA7_INTR_VECT, dma_rec_interrupt,
- + IRQF_DISABLED, "serial 0 dma rec",
- + &serial_cris_ports[0]))
- + panic("irq ser0rxdma");
- + crisv32_request_dma(7, "ser0", DMA_PANIC_ON_ERROR, 0,
- + dma_ser0);
- +#endif
- + } else if (port->line == 1) {
- + if (request_irq(SER1_INTR_VECT, ser_interrupt,
- + IRQF_DISABLED, "ser1",
- + &serial_cris_ports[1]))
- + panic("irq ser1");
- +
- + /* Port ser1 can use dma4 for tx and dma5 for rx. */
- +#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA4_OUT
- + if (request_irq(DMA4_INTR_VECT, dma_tr_interrupt,
- + IRQF_DISABLED, "serial 1 dma tr",
- + &serial_cris_ports[1]))
- + panic("irq ser1txdma");
- + crisv32_request_dma(4, "ser1", DMA_PANIC_ON_ERROR, 0,
- + dma_ser1);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA5_IN
- + if (request_irq(DMA5_INTR_VECT, dma_rec_interrupt,
- + IRQF_DISABLED, "serial 1 dma rec",
- + &serial_cris_ports[1]))
- + panic("irq ser1rxdma");
- + crisv32_request_dma(5, "ser1", DMA_PANIC_ON_ERROR, 0,
- + dma_ser1);
- +#endif
- + } else if (port->line == 2) {
- + if (request_irq(SER2_INTR_VECT, ser_interrupt,
- + IRQF_DISABLED, "ser2",
- + &serial_cris_ports[2]))
- + panic("irq ser2");
- +
- + /* Port ser2 can use dma2 for tx and dma3 for rx. */
- +#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
- + if (request_irq(DMA2_INTR_VECT, dma_tr_interrupt,
- + IRQF_DISABLED, "serial 2 dma tr",
- + &serial_cris_ports[2]))
- + panic("irq ser2txdma");
- + crisv32_request_dma(2, "ser2", DMA_PANIC_ON_ERROR, 0,
- + dma_ser2);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
- + if (request_irq(DMA3_INTR_VECT, dma_rec_interrupt,
- + IRQF_DISABLED, "serial 2 dma rec",
- + &serial_cris_ports[2]))
- + panic("irq ser2rxdma");
- + crisv32_request_dma(3, "ser2", DMA_PANIC_ON_ERROR, 0,
- + dma_ser2);
- +#endif
- + } else if (port->line == 3) {
- + if (request_irq(SER3_INTR_VECT, ser_interrupt,
- + IRQF_DISABLED, "ser3",
- + &serial_cris_ports[3]))
- + panic("irq ser3" );
- +
- + /* Port ser3 can use dma8 for tx and dma9 for rx. */
- +#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA8_OUT
- + if (request_irq(DMA8_INTR_VECT, dma_tr_interrupt,
- + IRQF_DISABLED, "serial 3 dma tr",
- + &serial_cris_ports[3]))
- + panic("irq ser3txdma");
- + crisv32_request_dma(8, "ser3", DMA_PANIC_ON_ERROR, 0,
- + dma_ser3);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA9_IN
- + if (request_irq(DMA9_INTR_VECT, dma_rec_interrupt,
- + IRQF_DISABLED, "serial 3 dma rec",
- + &serial_cris_ports[3]))
- + panic("irq ser3rxdma");
- + crisv32_request_dma(9, "ser3", DMA_PANIC_ON_ERROR, 0,
- + dma_ser3);
- +#endif
- + }
- +#if CONFIG_ETRAX_SERIAL_PORTS == 5
- + else if (port->line == 4) {
- + if (request_irq(SER4_INTR_VECT, ser_interrupt,
- + IRQF_DISABLED, "ser4",
- + &serial_cris_ports[4]))
- + panic("irq ser4" );
- +
- +#ifdef CONFIG_ETRAX_SERIAL_PORT4_DMA_OUT
- + if (request_irq(DMA4_INTR_VECT, dma_tr_interrupt,
- + IRQF_DISABLED, "serial 4 dma tr",
- + &serial_cris_ports[4]))
- + panic("irq ser4txdma");
- + crisv32_request_dma(5, "ser4", DMA_PANIC_ON_ERROR, 0,
- + dma_ser4);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT4_DMA_IN
- + if (request_irq(DMA5_INTR_VECT, dma_rec_interrupt,
- + IRQF_DISABLED, "serial 4 dma rec",
- + &serial_cris_ports[4]))
- + panic("irq ser4rxdma");
- + crisv32_request_dma(5, "ser4", DMA_PANIC_ON_ERROR, 0,
- + dma_ser4);
- +#endif
- + }
- +#endif
- +
- + local_irq_save(flags);
- +
- + /*
- + * Reset the DMA channels and make sure their interrupts are cleared.
- + */
- +
- + regi_dma = up->regi_dmain;
- + if (regi_dma) {
- + reg_dma_rw_ack_intr ack_intr = { 0 };
- + DMA_RESET(regi_dma);
- + /* Wait until reset cycle is complete. */
- + DMA_WAIT_UNTIL_RESET(regi_dma);
- + REG_WR(dma, regi_dma, rw_cfg, cfg);
- + /* Make sure the irqs are cleared. */
- + ack_intr.group = 1;
- + ack_intr.ctxt = 1;
- + ack_intr.data = 1;
- + ack_intr.in_eop = 1;
- + ack_intr.stream_cmd = 1;
- + REG_WR(dma, regi_dma, rw_ack_intr, ack_intr);
- + }
- + regi_dma = up->regi_dmaout;
- + if (regi_dma) {
- + reg_dma_rw_ack_intr ack_intr = { 0 };
- + DMA_RESET(regi_dma);
- + /* Wait until reset cycle is complete. */
- + DMA_WAIT_UNTIL_RESET(regi_dma);
- + REG_WR(dma, regi_dma, rw_cfg, cfg);
- + /* Make sure the irqs are cleared. */
- + ack_intr.group = 1;
- + ack_intr.ctxt = 1;
- + ack_intr.data = 1;
- + ack_intr.in_eop = 1;
- + ack_intr.stream_cmd = 1;
- + REG_WR(dma, regi_dma, rw_ack_intr, ack_intr);
- + }
- +
- + REG_WR(ser, up->regi_ser, rw_intr_mask, ser_intr_mask);
- + if (up->regi_dmain)
- + REG_WR(dma, up->regi_dmain, rw_intr_mask, dmain_intr_mask);
- + if (up->regi_dmaout)
- + REG_WR(dma, up->regi_dmaout, rw_intr_mask, dmaout_intr_mask);
- +
- + start_receive(up);
- + start_transmitter(up);
- +
- + serial_cris_set_mctrl(&up->port, up->port.mctrl);
- +
- + local_irq_restore(flags);
- + spin_unlock(&up->port.lock);
- +
- + return 0;
- +}
- +
- +static void serial_cris_shutdown(struct uart_port *port)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + unsigned long flags;
- +
- + spin_lock_irqsave(&up->port.lock, flags);
- +
- + serial_cris_stop_tx(port);
- + serial_cris_stop_rx(port);
- +
- + if (port->line == 0) {
- + free_irq(SER0_INTR_VECT, &serial_cris_ports[0]);
- +#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
- + crisv32_free_dma(6);
- + free_irq(DMA6_INTR_VECT, &serial_cris_ports[0]);
- +#elif defined(CONFIG_ETRAX_SERIAL_PORT0_DMA0_OUT)
- + crisv32_free_dma(0);
- + free_irq(DMA0_INTR_VECT, &serial_cris_ports[0]);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
- + crisv32_free_dma(7);
- + free_irq(DMA7_INTR_VECT, &serial_cris_ports[0]);
- +#elif defined(CONFIG_ETRAX_SERIAL_PORT0_DMA1_IN)
- + crisv32_free_dma(1);
- + free_irq(DMA1_INTR_VECT, &serial_cris_ports[0]);
- +#endif
- + } else if (port->line == 1) {
- + free_irq(SER1_INTR_VECT, &serial_cris_ports[1]);
- +#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA4_OUT
- + crisv32_free_dma(4);
- + free_irq(DMA4_INTR_VECT, &serial_cris_ports[1]);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA5_IN
- + crisv32_free_dma(5);
- + free_irq(DMA5_INTR_VECT, &serial_cris_ports[1]);
- +#endif
- + } else if (port->line == 2) {
- + free_irq(SER2_INTR_VECT, &serial_cris_ports[2]);
- +#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
- + crisv32_free_dma(2);
- + free_irq(DMA2_INTR_VECT, &serial_cris_ports[2]);
- +#elif defined(CONFIG_ETRAX_SERIAL_PORT2_DMA6_OUT)
- + crisv32_free_dma(6);
- + free_irq(DMA6_INTR_VECT, &serial_cris_ports[2]);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
- + crisv32_free_dma(3);
- + free_irq(DMA3_INTR_VECT, &serial_cris_ports[2]);
- +#elif defined(CONFIG_ETRAX_SERIAL_PORT2_DMA7_IN)
- + crisv32_free_dma(7);
- + free_irq(DMA7_INTR_VECT, &serial_cris_ports[2]);
- +#endif
- + } else if (port->line == 3) {
- + free_irq(SER3_INTR_VECT, &serial_cris_ports[3]);
- +#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA8_OUT
- + crisv32_free_dma(8);
- + free_irq(DMA8_INTR_VECT, &serial_cris_ports[3]);
- +#elif defined(CONFIG_ETRAX_SERIAL_PORT3_DMA2_OUT)
- + crisv32_free_dma(2);
- + free_irq(DMA2_INTR_VECT, &serial_cris_ports[3]);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA9_IN
- + crisv32_free_dma(9);
- + free_irq(DMA9_INTR_VECT, &serial_cris_ports[3]);
- +#elif defined(CONFIG_ETRAX_SERIAL_PORT3_DMA3_IN)
- + crisv32_free_dma(3);
- + free_irq(DMA3_INTR_VECT, &serial_cris_ports[3]);
- +#endif
- + }
- +#if CONFIG_ETRAX_SERIAL_PORTS == 5
- + else if (port->line == 4) {
- + free_irq(SER4_INTR_VECT, &serial_cris_ports[4]);
- +#ifdef CONFIG_ETRAX_SERIAL_PORT4_DMA9_IN
- + crisv32_free_dma(9);
- + free_irq(DMA9_INTR_VECT, &serial_cris_ports[4]);
- +#endif
- + }
- +#endif
- +
- + serial_cris_set_mctrl(&up->port, up->port.mctrl);
- +
- + if (up->regi_dmain) {
- + struct etrax_recv_buffer *rb;
- + struct etrax_recv_buffer *rb_next;
- + int i;
- + struct dma_descr_data *descr;
- +
- + /*
- + * In case of DMA and receive errors, there might be pending
- + * receive buffers still linked here and not flushed upwards.
- + * Release them.
- + */
- + for (rb = up->first_recv_buffer; rb != NULL; rb = rb_next) {
- + rb_next = rb->next;
- + kfree (rb);
- + }
- + up->first_recv_buffer = NULL;
- + up->last_recv_buffer = NULL;
- +
- + /*
- + * Also release buffers that were attached to the DMA
- + * before we shut down the hardware above.
- + */
- + for (i = 0, descr = up->rec_descr;
- + i < SERIAL_RECV_DESCRIPTORS;
- + i++)
- + if (descr[i].buf) {
- + rb = phys_to_virt((u32) descr[i].buf)
- + - sizeof *rb;
- + kfree(rb);
- + descr[i].buf = NULL;
- + }
- + }
- +
- + spin_unlock_irqrestore(&up->port.lock, flags);
- +
- +}
- +
- +static void
- +serial_cris_set_termios(struct uart_port *port, struct ktermios *termios,
- + struct ktermios *old)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + unsigned long flags;
- + reg_ser_rw_xoff xoff;
- + reg_ser_rw_xoff_clr xoff_clr = {0};
- + reg_ser_rw_tr_ctrl tx_ctrl = {0};
- + reg_ser_rw_tr_dma_en tx_dma_en = {0};
- + reg_ser_rw_rec_ctrl rx_ctrl = {0};
- + reg_ser_rw_tr_baud_div tx_baud_div = {0};
- + reg_ser_rw_rec_baud_div rx_baud_div = {0};
- + reg_ser_r_stat_din rstat;
- + int baud;
- +
- + if (old &&
- + termios->c_cflag == old->c_cflag &&
- + termios->c_iflag == old->c_iflag)
- + return;
- +
- + /* Start with default settings and then fill in changes. */
- +
- + /* Tx: 8 bit, no/even parity, 1 stop bit, no cts. */
- + tx_ctrl.base_freq = regk_ser_f29_493;
- + tx_ctrl.en = 0;
- + tx_ctrl.stop = 0;
- +#ifdef CONFIG_ETRAX_RS485
- + if (up->rs485.enabled && (up->port_type != TYPE_485FD)) {
- + tx_ctrl.auto_rts = regk_ser_yes;
- + tx_ctrl.rts_setup = regk_ser_bits2;
- +
- + if (termios->c_cflag & CSTOPB) {
- + /* 2 stop bits. */
- + tx_ctrl.rts_delay = regk_ser_del2;
- + }
- + else {
- + /* 1 stop bits. */
- + tx_ctrl.rts_delay = regk_ser_del1;
- + }
- + } else
- +#endif
- + tx_ctrl.auto_rts = regk_ser_no;
- + tx_ctrl.txd = 1;
- + tx_ctrl.auto_cts = 0;
- + /* Rx: 8 bit, no/even parity. */
- + if (up->regi_dmain) {
- + rx_ctrl.dma_mode = 1;
- + rx_ctrl.auto_eop = 1;
- + }
- + rx_ctrl.dma_err = regk_ser_stop;
- + rx_ctrl.sampling = regk_ser_majority;
- + rx_ctrl.timeout = 1;
- +
- +#ifdef CONFIG_ETRAX_RS485
- + if (up->rs485.enabled && (up->port_type != TYPE_485FD)) {
- +# ifdef CONFIG_ETRAX_RS485_DISABLE_RECEIVER
- + rx_ctrl.half_duplex = regk_ser_yes;
- +# endif
- + rx_ctrl.rts_n = up->rs485.rts_after_sent ?
- + regk_ser_active : regk_ser_inactive;
- + } else if (up->port_type == TYPE_485FD) {
- + rx_ctrl.rts_n = regk_ser_active;
- + } else
- +#endif
- + rx_ctrl.rts_n = regk_ser_inactive;
- +
- + /* Common for tx and rx: 8N1. */
- + tx_ctrl.data_bits = regk_ser_bits8;
- + rx_ctrl.data_bits = regk_ser_bits8;
- + tx_ctrl.par = regk_ser_even;
- + rx_ctrl.par = regk_ser_even;
- + tx_ctrl.par_en = regk_ser_no;
- + rx_ctrl.par_en = regk_ser_no;
- +
- + tx_ctrl.stop_bits = regk_ser_bits1;
- +
- +
- + /* Change baud-rate and write it to the hardware. */
- +
- + /* baud_clock = base_freq / (divisor*8)
- + * divisor = base_freq / (baud_clock * 8)
- + * base_freq is either:
- + * off, ext, 29.493MHz, 32.000 MHz, 32.768 MHz or 100 MHz
- + * 20.493MHz is used for standard baudrates
- + */
- +
- + /*
- + * For the console port we keep the original baudrate here. Not very
- + * beautiful.
- + */
- + if ((port != console_port) || old)
- + baud = uart_get_baud_rate(port, termios, old, 0,
- + port->uartclk / 8);
- + else
- + baud = console_baud;
- +
- + tx_baud_div.div = 29493000 / (8 * baud);
- + /* Rx uses same as tx. */
- + rx_baud_div.div = tx_baud_div.div;
- + rx_ctrl.base_freq = tx_ctrl.base_freq;
- +
- + if ((termios->c_cflag & CSIZE) == CS7) {
- + /* Set 7 bit mode. */
- + tx_ctrl.data_bits = regk_ser_bits7;
- + rx_ctrl.data_bits = regk_ser_bits7;
- + }
- +
- + if (termios->c_cflag & CSTOPB) {
- + /* Set 2 stop bit mode. */
- + tx_ctrl.stop_bits = regk_ser_bits2;
- + }
- +
- + if (termios->c_cflag & PARENB) {
- + /* Enable parity. */
- + tx_ctrl.par_en = regk_ser_yes;
- + rx_ctrl.par_en = regk_ser_yes;
- + }
- +
- + if (termios->c_cflag & CMSPAR) {
- + if (termios->c_cflag & PARODD) {
- + /* Set mark parity if PARODD and CMSPAR. */
- + tx_ctrl.par = regk_ser_mark;
- + rx_ctrl.par = regk_ser_mark;
- + } else {
- + tx_ctrl.par = regk_ser_space;
- + rx_ctrl.par = regk_ser_space;
- + }
- + } else {
- + if (termios->c_cflag & PARODD) {
- + /* Set odd parity. */
- + tx_ctrl.par = regk_ser_odd;
- + rx_ctrl.par = regk_ser_odd;
- + }
- + }
- +
- + if (termios->c_cflag & CRTSCTS) {
- + /* Enable automatic CTS handling. */
- + tx_ctrl.auto_cts = regk_ser_yes;
- + }
- +
- + /* Make sure the tx and rx are enabled. */
- + tx_ctrl.en = regk_ser_yes;
- + rx_ctrl.en = regk_ser_yes;
- +
- + /*
- + * Wait for tr_idle in case a character is being output, so it won't
- + * be damaged by the changes we do below. It seems the termios
- + * changes "sometimes" (we can't see e.g. a tcsetattr TCSANOW
- + * parameter here) should take place no matter what state. However,
- + * in case we should wait, we may have a non-empty transmitter state
- + * as we tell the upper layers that we're all done when we've passed
- + * characters to the hardware, but we don't wait for them being
- + * actually shifted out.
- + */
- + spin_lock_irqsave(&port->lock, flags);
- +
- + /*
- + * None of our interrupts re-enable DMA, so it's thankfully ok to
- + * disable it once, outside the loop.
- + */
- + tx_dma_en.en = 0;
- + REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
- + do {
- + /*
- + * Make sure we have integrity between the read r_stat status
- + * and us writing the registers below, but don't busy-wait
- + * with interrupts off. We need to keep the port lock though
- + * (if we go SMP), so nobody else writes characters.
- + */
- + local_irq_restore(flags);
- + local_irq_save(flags);
- + rstat = REG_RD(ser, up->regi_ser, r_stat_din);
- + } while (!rstat.tr_idle);
- +
- + /* Actually write the control regs (if modified) to the hardware. */
- +
- + uart_update_timeout(port, termios->c_cflag, port->uartclk/8);
- + MODIFY_REG(up->regi_ser, rw_rec_baud_div, rx_baud_div);
- + MODIFY_REG(up->regi_ser, rw_rec_ctrl, rx_ctrl);
- +
- + MODIFY_REG(up->regi_ser, rw_tr_baud_div, tx_baud_div);
- + MODIFY_REG(up->regi_ser, rw_tr_ctrl, tx_ctrl);
- +
- + tx_dma_en.en = up->regi_dmaout != 0;
- + REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
- +
- + xoff = REG_RD(ser, up->regi_ser, rw_xoff);
- +
- + if (up->port.state && up->port.state->port.tty &&
- + (termios->c_iflag & IXON)) {
- + xoff.chr = STOP_CHAR(up->port.state->port.tty);
- + xoff.automatic = regk_ser_yes;
- + } else
- + xoff.automatic = regk_ser_no;
- +
- + MODIFY_REG(up->regi_ser, rw_xoff, xoff);
- +
- + /*
- + * Make sure we don't start in an automatically shut-off state due to
- + * a previous early exit.
- + */
- + xoff_clr.clr = 1;
- + REG_WR(ser, up->regi_ser, rw_xoff_clr, xoff_clr);
- +
- + serial_cris_set_mctrl(&up->port, up->port.mctrl);
- + spin_unlock_irqrestore(&up->port.lock, flags);
- +}
- +
- +static const char *
- +serial_cris_type(struct uart_port *port)
- +{
- + return "CRISv32";
- +}
- +
- +static void serial_cris_release_port(struct uart_port *port)
- +{
- +}
- +
- +static int serial_cris_request_port(struct uart_port *port)
- +{
- + return 0;
- +}
- +
- +static void serial_cris_config_port(struct uart_port *port, int flags)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + up->port.type = PORT_CRIS;
- +}
- +
- +#if defined(CONFIG_ETRAX_RS485)
- +
- +static void cris_set_rs485_mode(struct uart_cris_port* up) {
- + reg_ser_rw_tr_ctrl tr_ctrl;
- + reg_ser_rw_rec_ctrl rec_ctrl;
- + reg_scope_instances regi_ser = up->regi_ser;
- +
- + if (up->port_type == TYPE_485FD)
- + /* We do not want to change anything if we are in 485FD mode */
- + return;
- +
- + tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
- + rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
- +
- + /* Set port in RS-485 mode */
- + if (up->rs485.enabled) {
- + tr_ctrl.auto_rts = regk_ser_yes;
- + rec_ctrl.rts_n = up->rs485.rts_after_sent ?
- + regk_ser_active : regk_ser_inactive;
- + }
- + /* Set port to RS-232 mode */
- + else {
- + rec_ctrl.rts_n = regk_ser_inactive;
- + tr_ctrl.auto_rts = regk_ser_no;
- + rec_ctrl.half_duplex = regk_ser_no;
- + }
- +
- + REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
- + REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
- +}
- +
- +/* Enable/disable RS-485 mode on selected port. */
- +static int
- +cris_enable_rs485(struct uart_cris_port* up, struct rs485_control *r)
- +{
- + if (up->port_type == TYPE_485FD)
- + /* Port in 485FD mode can not chage mode */
- + goto out;
- +
- + up->rs485.enabled = 0x1 & r->enabled;
- + up->rs485.rts_on_send = 0x01 & r->rts_on_send;
- + up->rs485.rts_after_sent = 0x01 & r->rts_after_sent;
- + up->rs485.delay_rts_before_send = r->delay_rts_before_send;
- +
- + cris_set_rs485_mode(up);
- + out:
- + return 0;
- +}
- +
- +
- +/* Enable RS485 mode on port and send the data. Port will stay
- + * in 485 mode after the data has been sent.
- + */
- +static int
- +cris_write_rs485(struct uart_cris_port *up, const unsigned char* buf, int count)
- +{
- + up->rs485.enabled = 1;
- +
- + /* Set the port in RS485 mode */
- + cris_set_rs485_mode(up);
- +
- + /* Send the data */
- + count = serial_cris_driver.tty_driver->ops->write(up->port.state->port.tty, buf, count);
- +
- + return count;
- +}
- +
- +#endif /* CONFIG_ETRAX_RS485 */
- +
- +static int serial_cris_ioctl(struct uart_port *port, unsigned int cmd,
- + unsigned long arg)
- +{
- +#if defined(CONFIG_ETRAX_RS485)
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- +
- + switch (cmd) {
- + case TIOCSRS485: {
- + struct serial_rs485 in;
- + struct rs485_control rs485ctrl;
- + if (copy_from_user(&in, (struct serial_rs485 *)cmd,
- + sizeof(rs485ctrl)))
- + return -EFAULT;
- + rs485ctrl.rts_on_send = in.flags & SER_RS485_RTS_ON_SEND;
- + rs485ctrl.rts_after_sent = in.flags & SER_RS485_RTS_AFTER_SEND;
- + rs485ctrl.enabled = in.flags & SER_RS485_ENABLED;
- + rs485ctrl.delay_rts_before_send = in.delay_rts_before_send;
- +
- + return cris_enable_rs485(up, &rs485ctrl);
- + }
- +
- + case TIOCSERSETRS485: {
- + struct rs485_control rs485ctrl;
- + if (copy_from_user(&rs485ctrl, (struct rs485_control*) arg,
- + sizeof(rs485ctrl)))
- + return -EFAULT;
- +
- + return cris_enable_rs485(up, &rs485ctrl);
- + }
- +
- + case TIOCSERWRRS485: {
- + struct rs485_write rs485wr;
- + if (copy_from_user(&rs485wr, (struct rs485_write*)arg,
- + sizeof(rs485wr)))
- + return -EFAULT;
- +
- + return cris_write_rs485(up, rs485wr.outc, rs485wr.outc_size);
- + }
- +
- + case TIOCSERSETRS485FD: {
- + reg_scope_instances regi_ser = up->regi_ser;
- + reg_ser_rw_rec_ctrl rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
- +
- + if (arg)
- + rec_ctrl.half_duplex = regk_ser_no;
- + else
- + rec_ctrl.half_duplex = regk_ser_yes;
- +
- + REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
- + return 0;
- + }
- +
- + case TIOCSERSETDIVISOR: {
- + reg_ser_rw_tr_baud_div tx_baud_div = {0};
- + reg_ser_rw_rec_baud_div rx_baud_div = {0};
- +
- + /* divisor must be >= 8 */
- + if (arg < 8)
- + return -EINVAL;
- +
- + tx_baud_div.div = arg;
- + rx_baud_div.div = tx_baud_div.div; /* same as tx. */
- +
- + MODIFY_REG(up->regi_ser, rw_rec_baud_div, rx_baud_div);
- + MODIFY_REG(up->regi_ser, rw_tr_baud_div, tx_baud_div);
- +
- + return 0;
- + }
- +
- + default:
- + return -ENOIOCTLCMD;
- + }
- +
- + return 0;
- +#else
- + return -ENOIOCTLCMD;
- +#endif
- +}
- +
- +static const struct uart_ops serial_cris_pops = {
- + .tx_empty = serial_cris_tx_empty,
- + .set_mctrl = serial_cris_set_mctrl,
- + .get_mctrl = serial_cris_get_mctrl,
- + .stop_tx = serial_cris_stop_tx,
- + .start_tx = serial_cris_start_tx,
- + .send_xchar = serial_cris_send_xchar,
- + .stop_rx = serial_cris_stop_rx,
- + .enable_ms = serial_cris_enable_ms,
- + .break_ctl = serial_cris_break_ctl,
- + .startup = serial_cris_startup,
- + .shutdown = serial_cris_shutdown,
- + .set_termios = serial_cris_set_termios,
- + .type = serial_cris_type,
- + .release_port = serial_cris_release_port,
- + .request_port = serial_cris_request_port,
- + .config_port = serial_cris_config_port,
- + .ioctl = serial_cris_ioctl,
- +#ifdef CONFIG_CONSOLE_POLL
- + .poll_get_char = serial_artpec_get_poll_char,
- + .poll_put_char = serial_artpec_put_poll_char,
- +#endif
- +};
- +
- +/*
- + * It's too easy to break CONFIG_ETRAX_DEBUG_PORT_NULL and the
- + * no-config choices by adding and moving code to before a necessary
- + * early exit in all functions for the special case of
- + * up->regi_ser == 0. This collection of dummy functions lets us
- + * avoid that. Maybe there should be a generic table of dummy serial
- + * functions?
- + */
- +
- +static unsigned int serial_cris_tx_empty_dummy(struct uart_port *port)
- +{
- + return TIOCSER_TEMT;
- +}
- +
- +static void serial_cris_set_mctrl_dummy(struct uart_port *port,
- + unsigned int mctrl)
- +{
- +}
- +
- +static unsigned int serial_cris_get_mctrl_dummy(struct uart_port *port)
- +{
- + return 0;
- +}
- +
- +static void serial_cris_stop_tx_dummy(struct uart_port *port)
- +{
- +}
- +
- +static void serial_cris_start_tx_dummy(struct uart_port *port)
- +{
- + /* Discard outbound characters. */
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + struct circ_buf *xmit = &up->port.state->xmit;
- + xmit->tail = xmit->head;
- + uart_write_wakeup(port);
- +}
- +
- +#define serial_cris_stop_rx_dummy serial_cris_stop_tx_dummy
- +
- +#define serial_cris_enable_ms_dummy serial_cris_stop_tx_dummy
- +
- +static void serial_cris_break_ctl_dummy(struct uart_port *port,
- + int break_state)
- +{
- +}
- +
- +static int serial_cris_startup_dummy(struct uart_port *port)
- +{
- + return 0;
- +}
- +
- +#define serial_cris_shutdown_dummy serial_cris_stop_tx_dummy
- +
- +static void
- +serial_cris_set_termios_dummy(struct uart_port *port, struct ktermios *termios,
- + struct ktermios *old)
- +{
- +}
- +
- +#define serial_cris_release_port_dummy serial_cris_stop_tx_dummy
- +#define serial_cris_request_port_dummy serial_cris_startup_dummy
- +
- +static const struct uart_ops serial_cris_dummy_pops = {
- + /*
- + * We *could* save one or two of those with different
- + * signature by casting and knowledge of the ABI, but it's
- + * just not worth the maintenance headache.
- + * For the ones we don't define here, the default (usually meaning
- + * "unimplemented") makes sense.
- + */
- + .tx_empty = serial_cris_tx_empty_dummy,
- + .set_mctrl = serial_cris_set_mctrl_dummy,
- + .get_mctrl = serial_cris_get_mctrl_dummy,
- + .stop_tx = serial_cris_stop_tx_dummy,
- + .start_tx = serial_cris_start_tx_dummy,
- + .stop_rx = serial_cris_stop_rx_dummy,
- + .enable_ms = serial_cris_enable_ms_dummy,
- + .break_ctl = serial_cris_break_ctl_dummy,
- + .startup = serial_cris_startup_dummy,
- + .shutdown = serial_cris_shutdown_dummy,
- + .set_termios = serial_cris_set_termios_dummy,
- +
- + /* This one we keep the same. */
- + .type = serial_cris_type,
- +
- + .release_port = serial_cris_release_port_dummy,
- + .request_port = serial_cris_request_port_dummy,
- +
- + /*
- + * This one we keep the same too, as long as it doesn't do
- + * anything else but to set the type.
- + */
- + .config_port = serial_cris_config_port,
- +};
- +
- +static void cris_serial_port_init(struct uart_port *port, int line)
- +{
- + struct uart_cris_port *up = (struct uart_cris_port *)port;
- + static int first = 1;
- +
- + if (up->initialized)
- + return;
- + up->initialized = 1;
- + port->line = line;
- + spin_lock_init(&port->lock);
- + port->ops =
- + up->regi_ser == 0 ? &serial_cris_dummy_pops :
- + &serial_cris_pops;
- + port->irq = up->irq;
- + port->iobase = up->regi_ser ? up->regi_ser : 1;
- + port->uartclk = 29493000;
- +
- + /*
- + * We can't fit any more than 255 here (unsigned char), though
- + * actually UART_XMIT_SIZE characters could be pending output (if it
- + * wasn't for the single test in transmit_chars_dma). At time of this
- + * writing, the definition of "fifosize" is here the amount of
- + * characters that can be pending output after a start_tx call until
- + * tx_empty returns 1: see serial_core.c:uart_wait_until_sent. This
- + * matters for timeout calculations unfortunately, but keeping larger
- + * amounts at the DMA wouldn't win much so let's just play nice.
- + */
- + port->fifosize = 255;
- + port->flags = UPF_BOOT_AUTOCONF;
- +
- +#ifdef CONFIG_ETRAX_RS485
- + /* Set sane defaults. */
- + up->rs485.rts_on_send = 0;
- + up->rs485.rts_after_sent = 1;
- + up->rs485.delay_rts_before_send = 0;
- + if (up->port_type > TYPE_232)
- + up->rs485.enabled = 1;
- + else
- + up->rs485.enabled = 0;
- +#endif
- +
- + if (first) {
- + first = 0;
- +#ifdef CONFIG_ETRAX_SERIAL_PORT0
- + SETUP_PINS(0);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT1
- + SETUP_PINS(1);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT2
- + SETUP_PINS(2);
- +#endif
- +#ifdef CONFIG_ETRAX_SERIAL_PORT3
- + SETUP_PINS(3);
- +#endif
- + }
- +}
- +
- +static int __init serial_cris_init(void)
- +{
- + int ret, i;
- + printk(KERN_INFO "Serial: CRISv32 driver $Revision: 1.109 $ ");
- +
- + ret = uart_register_driver(&serial_cris_driver);
- + if (ret)
- + goto out;
- +
- + for (i = 0; i < UART_NR; i++) {
- + if (serial_cris_ports[i].used) {
- + struct uart_port *port;
- +#ifdef CONFIG_ETRAX_RS485
- + reg_ser_rw_rec_ctrl rec_ctrl;
- +
- + /* Make sure that the RTS pin stays low when allocating
- + * pins for a port in 485 mode.
- + */
- + if (serial_cris_ports[i].port_type > TYPE_232) {
- + rec_ctrl = REG_RD(ser, serial_cris_ports[i].regi_ser, rw_rec_ctrl);
- + rec_ctrl.rts_n = regk_ser_active;
- + REG_WR(ser, serial_cris_ports[i].regi_ser, rw_rec_ctrl, rec_ctrl);
- + }
- +#endif
- + switch (serial_cris_ports[i].regi_ser) {
- + case regi_ser0:
- + break;
- + case regi_ser1:
- + if (crisv32_pinmux_alloc_fixed(pinmux_ser1)) {
- + printk("Failed to allocate pins for ser1, disable port\n");
- + serial_cris_ports[i].used = 0;
- + continue;
- + }
- + break;
- + case regi_ser2:
- + if (crisv32_pinmux_alloc_fixed(pinmux_ser2)) {
- + printk("Failed to allocate pins for ser2, disable port\n");
- + serial_cris_ports[i].used = 0;
- + continue;
- + }
- + break;
- + case regi_ser3:
- + if (crisv32_pinmux_alloc_fixed(pinmux_ser3)) {
- + printk("Failed to allocate pins for ser3, disable port\n");
- + serial_cris_ports[i].used = 0;
- + continue;
- + }
- + break;
- +#if CONFIG_ETRAX_SERIAL_PORTS == 5
- + case regi_ser4:
- + if (crisv32_pinmux_alloc_fixed(pinmux_ser4)) {
- + printk("Failed to allocate pins for ser4, disable port\n");
- + serial_cris_ports[i].used = 0;
- + continue;
- + }
- + break;
- +#endif
- + default:
- + printk("Error: No such serial port (%d) \n", serial_cris_ports[i].regi_ser);
- + serial_cris_ports[i].used = 0;
- + break;
- + }
- +
- + port = &serial_cris_ports[i].port;
- + cris_console.index = i;
- + cris_serial_port_init(port, i);
- + uart_add_one_port(&serial_cris_driver, port);
- + }
- + }
- +
- +out:
- + return ret;
- +}
- +
- +static void __exit serial_cris_exit(void)
- +{
- + int i;
- + for (i = 0; i < UART_NR; i++)
- + if (serial_cris_ports[i].used) {
- + switch (serial_cris_ports[i].regi_ser) {
- + case regi_ser1:
- + crisv32_pinmux_dealloc_fixed(pinmux_ser1);
- + break;
- + case regi_ser2:
- + crisv32_pinmux_dealloc_fixed(pinmux_ser2);
- + break;
- + case regi_ser3:
- + crisv32_pinmux_dealloc_fixed(pinmux_ser3);
- + break;
- +#if CONFIG_ETRAX_SERIAL_PORTS == 5
- + case regi_ser4:
- + crisv32_pinmux_dealloc_fixed(pinmux_ser4);
- + break;
- +#endif
- + default:
- + printk("Error: No such serial port (%d) \n", serial_cris_ports[i].regi_ser);
- + serial_cris_ports[i].used = 0;
- + break;
- + }
- + uart_remove_one_port(&serial_cris_driver,
- + &serial_cris_ports[i].port);
- + }
- + uart_unregister_driver(&serial_cris_driver);
- +}
- +
- +module_init(serial_cris_init);
- +module_exit(serial_cris_exit);
- diff -Nur linux-4.0.3.orig/drivers/tty/serial/Makefile linux-4.0.3/drivers/tty/serial/Makefile
- --- linux-4.0.3.orig/drivers/tty/serial/Makefile 2015-05-13 14:14:53.000000000 +0200
- +++ linux-4.0.3/drivers/tty/serial/Makefile 2015-05-25 17:21:47.000000000 +0200
- @@ -51,6 +51,7 @@
- obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
- obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
- obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
- +obj-$(CONFIG_ETRAXFS_SERIAL) += crisv32.o
- obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o
- obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
- obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
- diff -Nur linux-4.0.3.orig/include/uapi/linux/serial_core.h linux-4.0.3/include/uapi/linux/serial_core.h
- --- linux-4.0.3.orig/include/uapi/linux/serial_core.h 2015-05-13 14:14:53.000000000 +0200
- +++ linux-4.0.3/include/uapi/linux/serial_core.h 2015-05-25 17:20:56.000000000 +0200
- @@ -258,4 +258,7 @@
- /* Cris v10 / v32 SoC */
- #define PORT_CRIS 112
-
- +/* Cris v10 / v32 SoC */
- +#define PORT_CRIS 109
- +
- #endif /* _UAPILINUX_SERIAL_CORE_H */
|