0001
0002
0003
0004 #include <linux/kernel.h>
0005 #include <linux/errno.h>
0006 #include <linux/slab.h>
0007 #include <linux/list.h>
0008 #include <linux/slimbus.h>
0009 #include <uapi/sound/asound.h>
0010 #include "slimbus.h"
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 static const struct segdist_code {
0024 int ratem;
0025 int seg_interval;
0026 int segdist_code;
0027 u32 seg_offset_mask;
0028
0029 } segdist_codes[] = {
0030 {1, 1536, 0x200, 0xdff},
0031 {2, 768, 0x100, 0xcff},
0032 {4, 384, 0x080, 0xc7f},
0033 {8, 192, 0x040, 0xc3f},
0034 {16, 96, 0x020, 0xc1f},
0035 {32, 48, 0x010, 0xc0f},
0036 {64, 24, 0x008, 0xc07},
0037 {128, 12, 0x004, 0xc03},
0038 {256, 6, 0x002, 0xc01},
0039 {512, 3, 0x001, 0xc00},
0040 {3, 512, 0xe00, 0x1ff},
0041 {6, 256, 0xd00, 0x0ff},
0042 {12, 128, 0xc80, 0x07f},
0043 {24, 64, 0xc40, 0x03f},
0044 {48, 32, 0xc20, 0x01f},
0045 {96, 16, 0xc10, 0x00f},
0046 {192, 8, 0xc08, 0x007},
0047 {364, 4, 0xc04, 0x003},
0048 {768, 2, 0xc02, 0x001},
0049 };
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060 static const int slim_presence_rate_table[] = {
0061 0,
0062 12000,
0063 24000,
0064 48000,
0065 96000,
0066 192000,
0067 384000,
0068 768000,
0069 0,
0070 110250,
0071 220500,
0072 441000,
0073 882000,
0074 176400,
0075 352800,
0076 705600,
0077 4000,
0078 8000,
0079 16000,
0080 32000,
0081 64000,
0082 128000,
0083 256000,
0084 512000,
0085 };
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099 struct slim_stream_runtime *slim_stream_allocate(struct slim_device *dev,
0100 const char *name)
0101 {
0102 struct slim_stream_runtime *rt;
0103
0104 rt = kzalloc(sizeof(*rt), GFP_KERNEL);
0105 if (!rt)
0106 return ERR_PTR(-ENOMEM);
0107
0108 rt->name = kasprintf(GFP_KERNEL, "slim-%s", name);
0109 if (!rt->name) {
0110 kfree(rt);
0111 return ERR_PTR(-ENOMEM);
0112 }
0113
0114 rt->dev = dev;
0115 spin_lock(&dev->stream_list_lock);
0116 list_add_tail(&rt->node, &dev->stream_list);
0117 spin_unlock(&dev->stream_list_lock);
0118
0119 return rt;
0120 }
0121 EXPORT_SYMBOL_GPL(slim_stream_allocate);
0122
0123 static int slim_connect_port_channel(struct slim_stream_runtime *stream,
0124 struct slim_port *port)
0125 {
0126 struct slim_device *sdev = stream->dev;
0127 u8 wbuf[2];
0128 struct slim_val_inf msg = {0, 2, NULL, wbuf, NULL};
0129 u8 mc = SLIM_MSG_MC_CONNECT_SOURCE;
0130 DEFINE_SLIM_LDEST_TXN(txn, mc, 6, stream->dev->laddr, &msg);
0131
0132 if (port->direction == SLIM_PORT_SINK)
0133 txn.mc = SLIM_MSG_MC_CONNECT_SINK;
0134
0135 wbuf[0] = port->id;
0136 wbuf[1] = port->ch.id;
0137 port->ch.state = SLIM_CH_STATE_ASSOCIATED;
0138 port->state = SLIM_PORT_UNCONFIGURED;
0139
0140 return slim_do_transfer(sdev->ctrl, &txn);
0141 }
0142
0143 static int slim_disconnect_port(struct slim_stream_runtime *stream,
0144 struct slim_port *port)
0145 {
0146 struct slim_device *sdev = stream->dev;
0147 u8 wbuf[1];
0148 struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL};
0149 u8 mc = SLIM_MSG_MC_DISCONNECT_PORT;
0150 DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg);
0151
0152 wbuf[0] = port->id;
0153 port->ch.state = SLIM_CH_STATE_DISCONNECTED;
0154 port->state = SLIM_PORT_DISCONNECTED;
0155
0156 return slim_do_transfer(sdev->ctrl, &txn);
0157 }
0158
0159 static int slim_deactivate_remove_channel(struct slim_stream_runtime *stream,
0160 struct slim_port *port)
0161 {
0162 struct slim_device *sdev = stream->dev;
0163 u8 wbuf[1];
0164 struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL};
0165 u8 mc = SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL;
0166 DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg);
0167 int ret;
0168
0169 wbuf[0] = port->ch.id;
0170 ret = slim_do_transfer(sdev->ctrl, &txn);
0171 if (ret)
0172 return ret;
0173
0174 txn.mc = SLIM_MSG_MC_NEXT_REMOVE_CHANNEL;
0175 port->ch.state = SLIM_CH_STATE_REMOVED;
0176
0177 return slim_do_transfer(sdev->ctrl, &txn);
0178 }
0179
0180 static int slim_get_prate_code(int rate)
0181 {
0182 int i;
0183
0184 for (i = 0; i < ARRAY_SIZE(slim_presence_rate_table); i++) {
0185 if (rate == slim_presence_rate_table[i])
0186 return i;
0187 }
0188
0189 return -EINVAL;
0190 }
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 int slim_stream_prepare(struct slim_stream_runtime *rt,
0203 struct slim_stream_config *cfg)
0204 {
0205 struct slim_controller *ctrl = rt->dev->ctrl;
0206 struct slim_port *port;
0207 int num_ports, i, port_id;
0208
0209 if (rt->ports) {
0210 dev_err(&rt->dev->dev, "Stream already Prepared\n");
0211 return -EINVAL;
0212 }
0213
0214 num_ports = hweight32(cfg->port_mask);
0215 rt->ports = kcalloc(num_ports, sizeof(*port), GFP_KERNEL);
0216 if (!rt->ports)
0217 return -ENOMEM;
0218
0219 rt->num_ports = num_ports;
0220 rt->rate = cfg->rate;
0221 rt->bps = cfg->bps;
0222 rt->direction = cfg->direction;
0223
0224 if (cfg->rate % ctrl->a_framer->superfreq) {
0225
0226
0227
0228
0229 if (cfg->direction == SNDRV_PCM_STREAM_PLAYBACK)
0230 rt->prot = SLIM_PROTO_PUSH;
0231 else
0232 rt->prot = SLIM_PROTO_PULL;
0233 } else {
0234 rt->prot = SLIM_PROTO_ISO;
0235 }
0236
0237 rt->ratem = cfg->rate/ctrl->a_framer->superfreq;
0238
0239 i = 0;
0240 for_each_set_bit(port_id, &cfg->port_mask, SLIM_DEVICE_MAX_PORTS) {
0241 port = &rt->ports[i];
0242 port->state = SLIM_PORT_DISCONNECTED;
0243 port->id = port_id;
0244 port->ch.prrate = slim_get_prate_code(cfg->rate);
0245 port->ch.id = cfg->chs[i];
0246 port->ch.data_fmt = SLIM_CH_DATA_FMT_NOT_DEFINED;
0247 port->ch.aux_fmt = SLIM_CH_AUX_FMT_NOT_APPLICABLE;
0248 port->ch.state = SLIM_CH_STATE_ALLOCATED;
0249
0250 if (cfg->direction == SNDRV_PCM_STREAM_PLAYBACK)
0251 port->direction = SLIM_PORT_SINK;
0252 else
0253 port->direction = SLIM_PORT_SOURCE;
0254
0255 slim_connect_port_channel(rt, port);
0256 i++;
0257 }
0258
0259 return 0;
0260 }
0261 EXPORT_SYMBOL_GPL(slim_stream_prepare);
0262
0263 static int slim_define_channel_content(struct slim_stream_runtime *stream,
0264 struct slim_port *port)
0265 {
0266 struct slim_device *sdev = stream->dev;
0267 u8 wbuf[4];
0268 struct slim_val_inf msg = {0, 4, NULL, wbuf, NULL};
0269 u8 mc = SLIM_MSG_MC_NEXT_DEFINE_CONTENT;
0270 DEFINE_SLIM_LDEST_TXN(txn, mc, 8, stream->dev->laddr, &msg);
0271
0272 wbuf[0] = port->ch.id;
0273 wbuf[1] = port->ch.prrate;
0274
0275
0276 if (stream->prot != SLIM_PROTO_ISO)
0277 wbuf[1] |= SLIM_CHANNEL_CONTENT_FL;
0278
0279 wbuf[2] = port->ch.data_fmt | (port->ch.aux_fmt << 4);
0280 wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS;
0281 port->ch.state = SLIM_CH_STATE_CONTENT_DEFINED;
0282
0283 return slim_do_transfer(sdev->ctrl, &txn);
0284 }
0285
0286 static int slim_get_segdist_code(int ratem)
0287 {
0288 int i;
0289
0290 for (i = 0; i < ARRAY_SIZE(segdist_codes); i++) {
0291 if (segdist_codes[i].ratem == ratem)
0292 return segdist_codes[i].segdist_code;
0293 }
0294
0295 return -EINVAL;
0296 }
0297
0298 static int slim_define_channel(struct slim_stream_runtime *stream,
0299 struct slim_port *port)
0300 {
0301 struct slim_device *sdev = stream->dev;
0302 u8 wbuf[4];
0303 struct slim_val_inf msg = {0, 4, NULL, wbuf, NULL};
0304 u8 mc = SLIM_MSG_MC_NEXT_DEFINE_CHANNEL;
0305 DEFINE_SLIM_LDEST_TXN(txn, mc, 8, stream->dev->laddr, &msg);
0306
0307 port->ch.seg_dist = slim_get_segdist_code(stream->ratem);
0308
0309 wbuf[0] = port->ch.id;
0310 wbuf[1] = port->ch.seg_dist & 0xFF;
0311 wbuf[2] = (stream->prot << 4) | ((port->ch.seg_dist & 0xF00) >> 8);
0312 if (stream->prot == SLIM_PROTO_ISO)
0313 wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS;
0314 else
0315 wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS + 1;
0316
0317 port->ch.state = SLIM_CH_STATE_DEFINED;
0318
0319 return slim_do_transfer(sdev->ctrl, &txn);
0320 }
0321
0322 static int slim_activate_channel(struct slim_stream_runtime *stream,
0323 struct slim_port *port)
0324 {
0325 struct slim_device *sdev = stream->dev;
0326 u8 wbuf[1];
0327 struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL};
0328 u8 mc = SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL;
0329 DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg);
0330
0331 txn.msg->num_bytes = 1;
0332 txn.msg->wbuf = wbuf;
0333 wbuf[0] = port->ch.id;
0334 port->ch.state = SLIM_CH_STATE_ACTIVE;
0335
0336 return slim_do_transfer(sdev->ctrl, &txn);
0337 }
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350 int slim_stream_enable(struct slim_stream_runtime *stream)
0351 {
0352 DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
0353 3, SLIM_LA_MANAGER, NULL);
0354 struct slim_controller *ctrl = stream->dev->ctrl;
0355 int ret, i;
0356
0357 if (ctrl->enable_stream) {
0358 ret = ctrl->enable_stream(stream);
0359 if (ret)
0360 return ret;
0361
0362 for (i = 0; i < stream->num_ports; i++)
0363 stream->ports[i].ch.state = SLIM_CH_STATE_ACTIVE;
0364
0365 return ret;
0366 }
0367
0368 ret = slim_do_transfer(ctrl, &txn);
0369 if (ret)
0370 return ret;
0371
0372
0373 for (i = 0; i < stream->num_ports; i++) {
0374 struct slim_port *port = &stream->ports[i];
0375
0376 slim_define_channel(stream, port);
0377 slim_define_channel_content(stream, port);
0378 }
0379
0380 for (i = 0; i < stream->num_ports; i++) {
0381 struct slim_port *port = &stream->ports[i];
0382
0383 slim_activate_channel(stream, port);
0384 port->state = SLIM_PORT_CONFIGURED;
0385 }
0386 txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
0387
0388 return slim_do_transfer(ctrl, &txn);
0389 }
0390 EXPORT_SYMBOL_GPL(slim_stream_enable);
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403 int slim_stream_disable(struct slim_stream_runtime *stream)
0404 {
0405 DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
0406 3, SLIM_LA_MANAGER, NULL);
0407 struct slim_controller *ctrl = stream->dev->ctrl;
0408 int ret, i;
0409
0410 if (ctrl->disable_stream)
0411 ctrl->disable_stream(stream);
0412
0413 ret = slim_do_transfer(ctrl, &txn);
0414 if (ret)
0415 return ret;
0416
0417 for (i = 0; i < stream->num_ports; i++)
0418 slim_deactivate_remove_channel(stream, &stream->ports[i]);
0419
0420 txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
0421
0422 return slim_do_transfer(ctrl, &txn);
0423 }
0424 EXPORT_SYMBOL_GPL(slim_stream_disable);
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437 int slim_stream_unprepare(struct slim_stream_runtime *stream)
0438 {
0439 int i;
0440
0441 for (i = 0; i < stream->num_ports; i++)
0442 slim_disconnect_port(stream, &stream->ports[i]);
0443
0444 kfree(stream->ports);
0445 stream->ports = NULL;
0446 stream->num_ports = 0;
0447
0448 return 0;
0449 }
0450 EXPORT_SYMBOL_GPL(slim_stream_unprepare);
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464 int slim_stream_free(struct slim_stream_runtime *stream)
0465 {
0466 struct slim_device *sdev = stream->dev;
0467
0468 spin_lock(&sdev->stream_list_lock);
0469 list_del(&stream->node);
0470 spin_unlock(&sdev->stream_list_lock);
0471
0472 kfree(stream->name);
0473 kfree(stream);
0474
0475 return 0;
0476 }
0477 EXPORT_SYMBOL_GPL(slim_stream_free);